xref: /plan9/sys/src/cmd/ssh1/sshnet.c (revision 63afb9a5d3f910047231762bcce0ee49fed3d07c)
1*63afb9a5SDavid du Colombier /*
2*63afb9a5SDavid du Colombier  * SSH network file system.
3*63afb9a5SDavid du Colombier  * Presents remote TCP stack as /net-style file system.
4*63afb9a5SDavid du Colombier  */
5*63afb9a5SDavid du Colombier 
6*63afb9a5SDavid du Colombier #include "ssh.h"
7*63afb9a5SDavid du Colombier #include <bio.h>
8*63afb9a5SDavid du Colombier #include <ndb.h>
9*63afb9a5SDavid du Colombier #include <thread.h>
10*63afb9a5SDavid du Colombier #include <fcall.h>
11*63afb9a5SDavid du Colombier #include <9p.h>
12*63afb9a5SDavid du Colombier 
13*63afb9a5SDavid du Colombier int rawhack = 1;
14*63afb9a5SDavid du Colombier Conn *conn;
15*63afb9a5SDavid du Colombier char *remoteip	= "<remote>";
16*63afb9a5SDavid du Colombier char *mtpt;
17*63afb9a5SDavid du Colombier 
18*63afb9a5SDavid du Colombier Cipher *allcipher[] = {
19*63afb9a5SDavid du Colombier 	&cipherrc4,
20*63afb9a5SDavid du Colombier 	&cipherblowfish,
21*63afb9a5SDavid du Colombier 	&cipher3des,
22*63afb9a5SDavid du Colombier 	&cipherdes,
23*63afb9a5SDavid du Colombier 	&ciphernone,
24*63afb9a5SDavid du Colombier 	&ciphertwiddle,
25*63afb9a5SDavid du Colombier };
26*63afb9a5SDavid du Colombier 
27*63afb9a5SDavid du Colombier Auth *allauth[] = {
28*63afb9a5SDavid du Colombier 	&authpassword,
29*63afb9a5SDavid du Colombier 	&authrsa,
30*63afb9a5SDavid du Colombier 	&authtis,
31*63afb9a5SDavid du Colombier };
32*63afb9a5SDavid du Colombier 
33*63afb9a5SDavid du Colombier char *cipherlist = "rc4 3des";
34*63afb9a5SDavid du Colombier char *authlist = "rsa password tis";
35*63afb9a5SDavid du Colombier 
36*63afb9a5SDavid du Colombier Cipher*
findcipher(char * name,Cipher ** list,int nlist)37*63afb9a5SDavid du Colombier findcipher(char *name, Cipher **list, int nlist)
38*63afb9a5SDavid du Colombier {
39*63afb9a5SDavid du Colombier 	int i;
40*63afb9a5SDavid du Colombier 
41*63afb9a5SDavid du Colombier 	for(i=0; i<nlist; i++)
42*63afb9a5SDavid du Colombier 		if(strcmp(name, list[i]->name) == 0)
43*63afb9a5SDavid du Colombier 			return list[i];
44*63afb9a5SDavid du Colombier 	error("unknown cipher %s", name);
45*63afb9a5SDavid du Colombier 	return nil;
46*63afb9a5SDavid du Colombier }
47*63afb9a5SDavid du Colombier 
48*63afb9a5SDavid du Colombier Auth*
findauth(char * name,Auth ** list,int nlist)49*63afb9a5SDavid du Colombier findauth(char *name, Auth **list, int nlist)
50*63afb9a5SDavid du Colombier {
51*63afb9a5SDavid du Colombier 	int i;
52*63afb9a5SDavid du Colombier 
53*63afb9a5SDavid du Colombier 	for(i=0; i<nlist; i++)
54*63afb9a5SDavid du Colombier 		if(strcmp(name, list[i]->name) == 0)
55*63afb9a5SDavid du Colombier 			return list[i];
56*63afb9a5SDavid du Colombier 	error("unknown auth %s", name);
57*63afb9a5SDavid du Colombier 	return nil;
58*63afb9a5SDavid du Colombier }
59*63afb9a5SDavid du Colombier 
60*63afb9a5SDavid du Colombier void
usage(void)61*63afb9a5SDavid du Colombier usage(void)
62*63afb9a5SDavid du Colombier {
63*63afb9a5SDavid du Colombier 	fprint(2, "usage: sshnet [-A authlist] [-c cipherlist] [-m mtpt] [user@]hostname\n");
64*63afb9a5SDavid du Colombier 	exits("usage");
65*63afb9a5SDavid du Colombier }
66*63afb9a5SDavid du Colombier 
67*63afb9a5SDavid du Colombier int
isatty(int fd)68*63afb9a5SDavid du Colombier isatty(int fd)
69*63afb9a5SDavid du Colombier {
70*63afb9a5SDavid du Colombier 	char buf[64];
71*63afb9a5SDavid du Colombier 
72*63afb9a5SDavid du Colombier 	buf[0] = '\0';
73*63afb9a5SDavid du Colombier 	fd2path(fd, buf, sizeof buf);
74*63afb9a5SDavid du Colombier 	if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
75*63afb9a5SDavid du Colombier 		return 1;
76*63afb9a5SDavid du Colombier 	return 0;
77*63afb9a5SDavid du Colombier }
78*63afb9a5SDavid du Colombier 
79*63afb9a5SDavid du Colombier enum
80*63afb9a5SDavid du Colombier {
81*63afb9a5SDavid du Colombier 	Qroot,
82*63afb9a5SDavid du Colombier 	Qcs,
83*63afb9a5SDavid du Colombier 	Qtcp,
84*63afb9a5SDavid du Colombier 	Qclone,
85*63afb9a5SDavid du Colombier 	Qn,
86*63afb9a5SDavid du Colombier 	Qctl,
87*63afb9a5SDavid du Colombier 	Qdata,
88*63afb9a5SDavid du Colombier 	Qlocal,
89*63afb9a5SDavid du Colombier 	Qremote,
90*63afb9a5SDavid du Colombier 	Qstatus,
91*63afb9a5SDavid du Colombier };
92*63afb9a5SDavid du Colombier 
93*63afb9a5SDavid du Colombier #define PATH(type, n)		((type)|((n)<<8))
94*63afb9a5SDavid du Colombier #define TYPE(path)			((int)(path) & 0xFF)
95*63afb9a5SDavid du Colombier #define NUM(path)			((uint)(path)>>8)
96*63afb9a5SDavid du Colombier 
97*63afb9a5SDavid du Colombier Channel *sshmsgchan;		/* chan(Msg*) */
98*63afb9a5SDavid du Colombier Channel *fsreqchan;			/* chan(Req*) */
99*63afb9a5SDavid du Colombier Channel *fsreqwaitchan;		/* chan(nil) */
100*63afb9a5SDavid du Colombier Channel *fsclunkchan;		/* chan(Fid*) */
101*63afb9a5SDavid du Colombier Channel *fsclunkwaitchan;	/* chan(nil) */
102*63afb9a5SDavid du Colombier ulong time0;
103*63afb9a5SDavid du Colombier 
104*63afb9a5SDavid du Colombier enum
105*63afb9a5SDavid du Colombier {
106*63afb9a5SDavid du Colombier 	Closed,
107*63afb9a5SDavid du Colombier 	Dialing,
108*63afb9a5SDavid du Colombier 	Established,
109*63afb9a5SDavid du Colombier 	Teardown,
110*63afb9a5SDavid du Colombier };
111*63afb9a5SDavid du Colombier 
112*63afb9a5SDavid du Colombier char *statestr[] = {
113*63afb9a5SDavid du Colombier 	"Closed",
114*63afb9a5SDavid du Colombier 	"Dialing",
115*63afb9a5SDavid du Colombier 	"Established",
116*63afb9a5SDavid du Colombier 	"Teardown",
117*63afb9a5SDavid du Colombier };
118*63afb9a5SDavid du Colombier 
119*63afb9a5SDavid du Colombier typedef struct Client Client;
120*63afb9a5SDavid du Colombier struct Client
121*63afb9a5SDavid du Colombier {
122*63afb9a5SDavid du Colombier 	int ref;
123*63afb9a5SDavid du Colombier 	int state;
124*63afb9a5SDavid du Colombier 	int num;
125*63afb9a5SDavid du Colombier 	int servernum;
126*63afb9a5SDavid du Colombier 	char *connect;
127*63afb9a5SDavid du Colombier 	Req *rq;
128*63afb9a5SDavid du Colombier 	Req **erq;
129*63afb9a5SDavid du Colombier 	Msg *mq;
130*63afb9a5SDavid du Colombier 	Msg **emq;
131*63afb9a5SDavid du Colombier };
132*63afb9a5SDavid du Colombier 
133*63afb9a5SDavid du Colombier int nclient;
134*63afb9a5SDavid du Colombier Client **client;
135*63afb9a5SDavid du Colombier 
136*63afb9a5SDavid du Colombier int
newclient(void)137*63afb9a5SDavid du Colombier newclient(void)
138*63afb9a5SDavid du Colombier {
139*63afb9a5SDavid du Colombier 	int i;
140*63afb9a5SDavid du Colombier 	Client *c;
141*63afb9a5SDavid du Colombier 
142*63afb9a5SDavid du Colombier 	for(i=0; i<nclient; i++)
143*63afb9a5SDavid du Colombier 		if(client[i]->ref==0 && client[i]->state == Closed)
144*63afb9a5SDavid du Colombier 			return i;
145*63afb9a5SDavid du Colombier 
146*63afb9a5SDavid du Colombier 	if(nclient%16 == 0)
147*63afb9a5SDavid du Colombier 		client = erealloc9p(client, (nclient+16)*sizeof(client[0]));
148*63afb9a5SDavid du Colombier 
149*63afb9a5SDavid du Colombier 	c = emalloc9p(sizeof(Client));
150*63afb9a5SDavid du Colombier 	memset(c, 0, sizeof(*c));
151*63afb9a5SDavid du Colombier 	c->num = nclient;
152*63afb9a5SDavid du Colombier 	client[nclient++] = c;
153*63afb9a5SDavid du Colombier 	return c->num;
154*63afb9a5SDavid du Colombier }
155*63afb9a5SDavid du Colombier 
156*63afb9a5SDavid du Colombier void
queuereq(Client * c,Req * r)157*63afb9a5SDavid du Colombier queuereq(Client *c, Req *r)
158*63afb9a5SDavid du Colombier {
159*63afb9a5SDavid du Colombier 	if(c->rq==nil)
160*63afb9a5SDavid du Colombier 		c->erq = &c->rq;
161*63afb9a5SDavid du Colombier 	*c->erq = r;
162*63afb9a5SDavid du Colombier 	r->aux = nil;
163*63afb9a5SDavid du Colombier 	c->erq = (Req**)&r->aux;
164*63afb9a5SDavid du Colombier }
165*63afb9a5SDavid du Colombier 
166*63afb9a5SDavid du Colombier void
queuemsg(Client * c,Msg * m)167*63afb9a5SDavid du Colombier queuemsg(Client *c, Msg *m)
168*63afb9a5SDavid du Colombier {
169*63afb9a5SDavid du Colombier 	if(c->mq==nil)
170*63afb9a5SDavid du Colombier 		c->emq = &c->mq;
171*63afb9a5SDavid du Colombier 	*c->emq = m;
172*63afb9a5SDavid du Colombier 	m->link = nil;
173*63afb9a5SDavid du Colombier 	c->emq = (Msg**)&m->link;
174*63afb9a5SDavid du Colombier }
175*63afb9a5SDavid du Colombier 
176*63afb9a5SDavid du Colombier void
matchmsgs(Client * c)177*63afb9a5SDavid du Colombier matchmsgs(Client *c)
178*63afb9a5SDavid du Colombier {
179*63afb9a5SDavid du Colombier 	Req *r;
180*63afb9a5SDavid du Colombier 	Msg *m;
181*63afb9a5SDavid du Colombier 	int n, rm;
182*63afb9a5SDavid du Colombier 
183*63afb9a5SDavid du Colombier 	while(c->rq && c->mq){
184*63afb9a5SDavid du Colombier 		r = c->rq;
185*63afb9a5SDavid du Colombier 		c->rq = r->aux;
186*63afb9a5SDavid du Colombier 
187*63afb9a5SDavid du Colombier 		rm = 0;
188*63afb9a5SDavid du Colombier 		m = c->mq;
189*63afb9a5SDavid du Colombier 		n = r->ifcall.count;
190*63afb9a5SDavid du Colombier 		if(n >= m->ep - m->rp){
191*63afb9a5SDavid du Colombier 			n = m->ep - m->rp;
192*63afb9a5SDavid du Colombier 			c->mq = m->link;
193*63afb9a5SDavid du Colombier 			rm = 1;
194*63afb9a5SDavid du Colombier 		}
195*63afb9a5SDavid du Colombier 		memmove(r->ofcall.data, m->rp, n);
196*63afb9a5SDavid du Colombier 		if(rm)
197*63afb9a5SDavid du Colombier 			free(m);
198*63afb9a5SDavid du Colombier 		else
199*63afb9a5SDavid du Colombier 			m->rp += n;
200*63afb9a5SDavid du Colombier 		r->ofcall.count = n;
201*63afb9a5SDavid du Colombier 		respond(r, nil);
202*63afb9a5SDavid du Colombier 	}
203*63afb9a5SDavid du Colombier }
204*63afb9a5SDavid du Colombier 
205*63afb9a5SDavid du Colombier Req*
findreq(Client * c,Req * r)206*63afb9a5SDavid du Colombier findreq(Client *c, Req *r)
207*63afb9a5SDavid du Colombier {
208*63afb9a5SDavid du Colombier 	Req **l;
209*63afb9a5SDavid du Colombier 
210*63afb9a5SDavid du Colombier 	for(l=&c->rq; *l; l=(Req**)&(*l)->aux){
211*63afb9a5SDavid du Colombier 		if(*l == r){
212*63afb9a5SDavid du Colombier 			*l = r->aux;
213*63afb9a5SDavid du Colombier 			if(*l == nil)
214*63afb9a5SDavid du Colombier 				c->erq = l;
215*63afb9a5SDavid du Colombier 			return r;
216*63afb9a5SDavid du Colombier 		}
217*63afb9a5SDavid du Colombier 	}
218*63afb9a5SDavid du Colombier 	return nil;
219*63afb9a5SDavid du Colombier }
220*63afb9a5SDavid du Colombier 
221*63afb9a5SDavid du Colombier void
dialedclient(Client * c)222*63afb9a5SDavid du Colombier dialedclient(Client *c)
223*63afb9a5SDavid du Colombier {
224*63afb9a5SDavid du Colombier 	Req *r;
225*63afb9a5SDavid du Colombier 
226*63afb9a5SDavid du Colombier 	if(r=c->rq){
227*63afb9a5SDavid du Colombier 		if(r->aux != nil)
228*63afb9a5SDavid du Colombier 			sysfatal("more than one outstanding dial request (BUG)");
229*63afb9a5SDavid du Colombier 		if(c->state == Established)
230*63afb9a5SDavid du Colombier 			respond(r, nil);
231*63afb9a5SDavid du Colombier 		else
232*63afb9a5SDavid du Colombier 			respond(r, "connect failed");
233*63afb9a5SDavid du Colombier 	}
234*63afb9a5SDavid du Colombier 	c->rq = nil;
235*63afb9a5SDavid du Colombier }
236*63afb9a5SDavid du Colombier 
237*63afb9a5SDavid du Colombier void
teardownclient(Client * c)238*63afb9a5SDavid du Colombier teardownclient(Client *c)
239*63afb9a5SDavid du Colombier {
240*63afb9a5SDavid du Colombier 	Msg *m;
241*63afb9a5SDavid du Colombier 
242*63afb9a5SDavid du Colombier 	c->state = Teardown;
243*63afb9a5SDavid du Colombier 	m = allocmsg(conn, SSH_MSG_CHANNEL_INPUT_EOF, 4);
244*63afb9a5SDavid du Colombier 	putlong(m, c->servernum);
245*63afb9a5SDavid du Colombier 	sendmsg(m);
246*63afb9a5SDavid du Colombier }
247*63afb9a5SDavid du Colombier 
248*63afb9a5SDavid du Colombier void
hangupclient(Client * c)249*63afb9a5SDavid du Colombier hangupclient(Client *c)
250*63afb9a5SDavid du Colombier {
251*63afb9a5SDavid du Colombier 	Req *r, *next;
252*63afb9a5SDavid du Colombier 	Msg *m, *mnext;
253*63afb9a5SDavid du Colombier 
254*63afb9a5SDavid du Colombier 	c->state = Closed;
255*63afb9a5SDavid du Colombier 	for(m=c->mq; m; m=mnext){
256*63afb9a5SDavid du Colombier 		mnext = m->link;
257*63afb9a5SDavid du Colombier 		free(m);
258*63afb9a5SDavid du Colombier 	}
259*63afb9a5SDavid du Colombier 	c->mq = nil;
260*63afb9a5SDavid du Colombier 	for(r=c->rq; r; r=next){
261*63afb9a5SDavid du Colombier 		next = r->aux;
262*63afb9a5SDavid du Colombier 		respond(r, "hangup on network connection");
263*63afb9a5SDavid du Colombier 	}
264*63afb9a5SDavid du Colombier 	c->rq = nil;
265*63afb9a5SDavid du Colombier }
266*63afb9a5SDavid du Colombier 
267*63afb9a5SDavid du Colombier void
closeclient(Client * c)268*63afb9a5SDavid du Colombier closeclient(Client *c)
269*63afb9a5SDavid du Colombier {
270*63afb9a5SDavid du Colombier 	Msg *m, *next;
271*63afb9a5SDavid du Colombier 
272*63afb9a5SDavid du Colombier 	if(--c->ref)
273*63afb9a5SDavid du Colombier 		return;
274*63afb9a5SDavid du Colombier 
275*63afb9a5SDavid du Colombier 	if(c->rq != nil)
276*63afb9a5SDavid du Colombier 		sysfatal("ref count reached zero with requests pending (BUG)");
277*63afb9a5SDavid du Colombier 
278*63afb9a5SDavid du Colombier 	for(m=c->mq; m; m=next){
279*63afb9a5SDavid du Colombier 		next = m->link;
280*63afb9a5SDavid du Colombier 		free(m);
281*63afb9a5SDavid du Colombier 	}
282*63afb9a5SDavid du Colombier 	c->mq = nil;
283*63afb9a5SDavid du Colombier 
284*63afb9a5SDavid du Colombier 	if(c->state != Closed)
285*63afb9a5SDavid du Colombier 		teardownclient(c);
286*63afb9a5SDavid du Colombier }
287*63afb9a5SDavid du Colombier 
288*63afb9a5SDavid du Colombier 
289*63afb9a5SDavid du Colombier void
sshreadproc(void * a)290*63afb9a5SDavid du Colombier sshreadproc(void *a)
291*63afb9a5SDavid du Colombier {
292*63afb9a5SDavid du Colombier 	Conn *c;
293*63afb9a5SDavid du Colombier 	Msg *m;
294*63afb9a5SDavid du Colombier 
295*63afb9a5SDavid du Colombier 	c = a;
296*63afb9a5SDavid du Colombier 	for(;;){
297*63afb9a5SDavid du Colombier 		m = recvmsg(c, -1);
298*63afb9a5SDavid du Colombier 		if(m == nil)
299*63afb9a5SDavid du Colombier 			sysfatal("eof on ssh connection");
300*63afb9a5SDavid du Colombier 		sendp(sshmsgchan, m);
301*63afb9a5SDavid du Colombier 	}
302*63afb9a5SDavid du Colombier }
303*63afb9a5SDavid du Colombier 
304*63afb9a5SDavid du Colombier typedef struct Tab Tab;
305*63afb9a5SDavid du Colombier struct Tab
306*63afb9a5SDavid du Colombier {
307*63afb9a5SDavid du Colombier 	char *name;
308*63afb9a5SDavid du Colombier 	ulong mode;
309*63afb9a5SDavid du Colombier };
310*63afb9a5SDavid du Colombier 
311*63afb9a5SDavid du Colombier Tab tab[] =
312*63afb9a5SDavid du Colombier {
313*63afb9a5SDavid du Colombier 	"/",		DMDIR|0555,
314*63afb9a5SDavid du Colombier 	"cs",		0666,
315*63afb9a5SDavid du Colombier 	"tcp",	DMDIR|0555,
316*63afb9a5SDavid du Colombier 	"clone",	0666,
317*63afb9a5SDavid du Colombier 	nil,		DMDIR|0555,
318*63afb9a5SDavid du Colombier 	"ctl",		0666,
319*63afb9a5SDavid du Colombier 	"data",	0666,
320*63afb9a5SDavid du Colombier 	"local",	0444,
321*63afb9a5SDavid du Colombier 	"remote",	0444,
322*63afb9a5SDavid du Colombier 	"status",	0444,
323*63afb9a5SDavid du Colombier };
324*63afb9a5SDavid du Colombier 
325*63afb9a5SDavid du Colombier static void
fillstat(Dir * d,uvlong path)326*63afb9a5SDavid du Colombier fillstat(Dir *d, uvlong path)
327*63afb9a5SDavid du Colombier {
328*63afb9a5SDavid du Colombier 	Tab *t;
329*63afb9a5SDavid du Colombier 
330*63afb9a5SDavid du Colombier 	memset(d, 0, sizeof(*d));
331*63afb9a5SDavid du Colombier 	d->uid = estrdup9p("ssh");
332*63afb9a5SDavid du Colombier 	d->gid = estrdup9p("ssh");
333*63afb9a5SDavid du Colombier 	d->qid.path = path;
334*63afb9a5SDavid du Colombier 	d->atime = d->mtime = time0;
335*63afb9a5SDavid du Colombier 	t = &tab[TYPE(path)];
336*63afb9a5SDavid du Colombier 	if(t->name)
337*63afb9a5SDavid du Colombier 		d->name = estrdup9p(t->name);
338*63afb9a5SDavid du Colombier 	else{
339*63afb9a5SDavid du Colombier 		d->name = smprint("%ud", NUM(path));
340*63afb9a5SDavid du Colombier 		if(d->name == nil)
341*63afb9a5SDavid du Colombier 			sysfatal("out of memory");
342*63afb9a5SDavid du Colombier 	}
343*63afb9a5SDavid du Colombier 	d->qid.type = t->mode>>24;
344*63afb9a5SDavid du Colombier 	d->mode = t->mode;
345*63afb9a5SDavid du Colombier }
346*63afb9a5SDavid du Colombier 
347*63afb9a5SDavid du Colombier static void
fsattach(Req * r)348*63afb9a5SDavid du Colombier fsattach(Req *r)
349*63afb9a5SDavid du Colombier {
350*63afb9a5SDavid du Colombier 	if(r->ifcall.aname && r->ifcall.aname[0]){
351*63afb9a5SDavid du Colombier 		respond(r, "invalid attach specifier");
352*63afb9a5SDavid du Colombier 		return;
353*63afb9a5SDavid du Colombier 	}
354*63afb9a5SDavid du Colombier 	r->fid->qid.path = PATH(Qroot, 0);
355*63afb9a5SDavid du Colombier 	r->fid->qid.type = QTDIR;
356*63afb9a5SDavid du Colombier 	r->fid->qid.vers = 0;
357*63afb9a5SDavid du Colombier 	r->ofcall.qid = r->fid->qid;
358*63afb9a5SDavid du Colombier 	respond(r, nil);
359*63afb9a5SDavid du Colombier }
360*63afb9a5SDavid du Colombier 
361*63afb9a5SDavid du Colombier static void
fsstat(Req * r)362*63afb9a5SDavid du Colombier fsstat(Req *r)
363*63afb9a5SDavid du Colombier {
364*63afb9a5SDavid du Colombier 	fillstat(&r->d, r->fid->qid.path);
365*63afb9a5SDavid du Colombier 	respond(r, nil);
366*63afb9a5SDavid du Colombier }
367*63afb9a5SDavid du Colombier 
368*63afb9a5SDavid du Colombier static int
rootgen(int i,Dir * d,void *)369*63afb9a5SDavid du Colombier rootgen(int i, Dir *d, void*)
370*63afb9a5SDavid du Colombier {
371*63afb9a5SDavid du Colombier 	i += Qroot+1;
372*63afb9a5SDavid du Colombier 	if(i <= Qtcp){
373*63afb9a5SDavid du Colombier 		fillstat(d, i);
374*63afb9a5SDavid du Colombier 		return 0;
375*63afb9a5SDavid du Colombier 	}
376*63afb9a5SDavid du Colombier 	return -1;
377*63afb9a5SDavid du Colombier }
378*63afb9a5SDavid du Colombier 
379*63afb9a5SDavid du Colombier static int
tcpgen(int i,Dir * d,void *)380*63afb9a5SDavid du Colombier tcpgen(int i, Dir *d, void*)
381*63afb9a5SDavid du Colombier {
382*63afb9a5SDavid du Colombier 	i += Qtcp+1;
383*63afb9a5SDavid du Colombier 	if(i < Qn){
384*63afb9a5SDavid du Colombier 		fillstat(d, i);
385*63afb9a5SDavid du Colombier 		return 0;
386*63afb9a5SDavid du Colombier 	}
387*63afb9a5SDavid du Colombier 	i -= Qn;
388*63afb9a5SDavid du Colombier 	if(i < nclient){
389*63afb9a5SDavid du Colombier 		fillstat(d, PATH(Qn, i));
390*63afb9a5SDavid du Colombier 		return 0;
391*63afb9a5SDavid du Colombier 	}
392*63afb9a5SDavid du Colombier 	return -1;
393*63afb9a5SDavid du Colombier }
394*63afb9a5SDavid du Colombier 
395*63afb9a5SDavid du Colombier static int
clientgen(int i,Dir * d,void * aux)396*63afb9a5SDavid du Colombier clientgen(int i, Dir *d, void *aux)
397*63afb9a5SDavid du Colombier {
398*63afb9a5SDavid du Colombier 	Client *c;
399*63afb9a5SDavid du Colombier 
400*63afb9a5SDavid du Colombier 	c = aux;
401*63afb9a5SDavid du Colombier 	i += Qn+1;
402*63afb9a5SDavid du Colombier 	if(i <= Qstatus){
403*63afb9a5SDavid du Colombier 		fillstat(d, PATH(i, c->num));
404*63afb9a5SDavid du Colombier 		return 0;
405*63afb9a5SDavid du Colombier 	}
406*63afb9a5SDavid du Colombier 	return -1;
407*63afb9a5SDavid du Colombier }
408*63afb9a5SDavid du Colombier 
409*63afb9a5SDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)410*63afb9a5SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
411*63afb9a5SDavid du Colombier {
412*63afb9a5SDavid du Colombier 	int i, n;
413*63afb9a5SDavid du Colombier 	char buf[32];
414*63afb9a5SDavid du Colombier 	ulong path;
415*63afb9a5SDavid du Colombier 
416*63afb9a5SDavid du Colombier 	path = fid->qid.path;
417*63afb9a5SDavid du Colombier 	if(!(fid->qid.type&QTDIR))
418*63afb9a5SDavid du Colombier 		return "walk in non-directory";
419*63afb9a5SDavid du Colombier 
420*63afb9a5SDavid du Colombier 	if(strcmp(name, "..") == 0){
421*63afb9a5SDavid du Colombier 		switch(TYPE(path)){
422*63afb9a5SDavid du Colombier 		case Qn:
423*63afb9a5SDavid du Colombier 			qid->path = PATH(Qtcp, NUM(path));
424*63afb9a5SDavid du Colombier 			qid->type = tab[Qtcp].mode>>24;
425*63afb9a5SDavid du Colombier 			return nil;
426*63afb9a5SDavid du Colombier 		case Qtcp:
427*63afb9a5SDavid du Colombier 			qid->path = PATH(Qroot, 0);
428*63afb9a5SDavid du Colombier 			qid->type = tab[Qroot].mode>>24;
429*63afb9a5SDavid du Colombier 			return nil;
430*63afb9a5SDavid du Colombier 		case Qroot:
431*63afb9a5SDavid du Colombier 			return nil;
432*63afb9a5SDavid du Colombier 		default:
433*63afb9a5SDavid du Colombier 			return "bug in fswalk1";
434*63afb9a5SDavid du Colombier 		}
435*63afb9a5SDavid du Colombier 	}
436*63afb9a5SDavid du Colombier 
437*63afb9a5SDavid du Colombier 	i = TYPE(path)+1;
438*63afb9a5SDavid du Colombier 	for(; i<nelem(tab); i++){
439*63afb9a5SDavid du Colombier 		if(i==Qn){
440*63afb9a5SDavid du Colombier 			n = atoi(name);
441*63afb9a5SDavid du Colombier 			snprint(buf, sizeof buf, "%d", n);
442*63afb9a5SDavid du Colombier 			if(n < nclient && strcmp(buf, name) == 0){
443*63afb9a5SDavid du Colombier 				qid->path = PATH(i, n);
444*63afb9a5SDavid du Colombier 				qid->type = tab[i].mode>>24;
445*63afb9a5SDavid du Colombier 				return nil;
446*63afb9a5SDavid du Colombier 			}
447*63afb9a5SDavid du Colombier 			break;
448*63afb9a5SDavid du Colombier 		}
449*63afb9a5SDavid du Colombier 		if(strcmp(name, tab[i].name) == 0){
450*63afb9a5SDavid du Colombier 			qid->path = PATH(i, NUM(path));
451*63afb9a5SDavid du Colombier 			qid->type = tab[i].mode>>24;
452*63afb9a5SDavid du Colombier 			return nil;
453*63afb9a5SDavid du Colombier 		}
454*63afb9a5SDavid du Colombier 		if(tab[i].mode&DMDIR)
455*63afb9a5SDavid du Colombier 			break;
456*63afb9a5SDavid du Colombier 	}
457*63afb9a5SDavid du Colombier 	return "directory entry not found";
458*63afb9a5SDavid du Colombier }
459*63afb9a5SDavid du Colombier 
460*63afb9a5SDavid du Colombier typedef struct Cs Cs;
461*63afb9a5SDavid du Colombier struct Cs
462*63afb9a5SDavid du Colombier {
463*63afb9a5SDavid du Colombier 	char *resp;
464*63afb9a5SDavid du Colombier 	int isnew;
465*63afb9a5SDavid du Colombier };
466*63afb9a5SDavid du Colombier 
467*63afb9a5SDavid du Colombier static int
ndbfindport(char * p)468*63afb9a5SDavid du Colombier ndbfindport(char *p)
469*63afb9a5SDavid du Colombier {
470*63afb9a5SDavid du Colombier 	char *s, *port;
471*63afb9a5SDavid du Colombier 	int n;
472*63afb9a5SDavid du Colombier 	static Ndb *db;
473*63afb9a5SDavid du Colombier 
474*63afb9a5SDavid du Colombier 	if(*p == '\0')
475*63afb9a5SDavid du Colombier 		return -1;
476*63afb9a5SDavid du Colombier 
477*63afb9a5SDavid du Colombier 	n = strtol(p, &s, 0);
478*63afb9a5SDavid du Colombier 	if(*s == '\0')
479*63afb9a5SDavid du Colombier 		return n;
480*63afb9a5SDavid du Colombier 
481*63afb9a5SDavid du Colombier 	if(db == nil){
482*63afb9a5SDavid du Colombier 		db = ndbopen("/lib/ndb/common");
483*63afb9a5SDavid du Colombier 		if(db == nil)
484*63afb9a5SDavid du Colombier 			return -1;
485*63afb9a5SDavid du Colombier 	}
486*63afb9a5SDavid du Colombier 
487*63afb9a5SDavid du Colombier 	port = ndbgetvalue(db, nil, "tcp", p, "port", nil);
488*63afb9a5SDavid du Colombier 	if(port == nil)
489*63afb9a5SDavid du Colombier 		return -1;
490*63afb9a5SDavid du Colombier 	n = atoi(port);
491*63afb9a5SDavid du Colombier 	free(port);
492*63afb9a5SDavid du Colombier 
493*63afb9a5SDavid du Colombier 	return n;
494*63afb9a5SDavid du Colombier }
495*63afb9a5SDavid du Colombier 
496*63afb9a5SDavid du Colombier static void
csread(Req * r)497*63afb9a5SDavid du Colombier csread(Req *r)
498*63afb9a5SDavid du Colombier {
499*63afb9a5SDavid du Colombier 	Cs *cs;
500*63afb9a5SDavid du Colombier 
501*63afb9a5SDavid du Colombier 	cs = r->fid->aux;
502*63afb9a5SDavid du Colombier 	if(cs->resp==nil){
503*63afb9a5SDavid du Colombier 		respond(r, "cs read without write");
504*63afb9a5SDavid du Colombier 		return;
505*63afb9a5SDavid du Colombier 	}
506*63afb9a5SDavid du Colombier 	if(r->ifcall.offset==0){
507*63afb9a5SDavid du Colombier 		if(!cs->isnew){
508*63afb9a5SDavid du Colombier 			r->ofcall.count = 0;
509*63afb9a5SDavid du Colombier 			respond(r, nil);
510*63afb9a5SDavid du Colombier 			return;
511*63afb9a5SDavid du Colombier 		}
512*63afb9a5SDavid du Colombier 		cs->isnew = 0;
513*63afb9a5SDavid du Colombier 	}
514*63afb9a5SDavid du Colombier 	readstr(r, cs->resp);
515*63afb9a5SDavid du Colombier 	respond(r, nil);
516*63afb9a5SDavid du Colombier }
517*63afb9a5SDavid du Colombier 
518*63afb9a5SDavid du Colombier static void
cswrite(Req * r)519*63afb9a5SDavid du Colombier cswrite(Req *r)
520*63afb9a5SDavid du Colombier {
521*63afb9a5SDavid du Colombier 	int port, nf;
522*63afb9a5SDavid du Colombier 	char err[ERRMAX], *f[4], *s, *ns;
523*63afb9a5SDavid du Colombier 	Cs *cs;
524*63afb9a5SDavid du Colombier 
525*63afb9a5SDavid du Colombier 	cs = r->fid->aux;
526*63afb9a5SDavid du Colombier 	s = emalloc(r->ifcall.count+1);
527*63afb9a5SDavid du Colombier 	memmove(s, r->ifcall.data, r->ifcall.count);
528*63afb9a5SDavid du Colombier 	s[r->ifcall.count] = '\0';
529*63afb9a5SDavid du Colombier 
530*63afb9a5SDavid du Colombier 	nf = getfields(s, f, nelem(f), 0, "!");
531*63afb9a5SDavid du Colombier 	if(nf != 3){
532*63afb9a5SDavid du Colombier 		free(s);
533*63afb9a5SDavid du Colombier 		respond(r, "can't translate");
534*63afb9a5SDavid du Colombier 		return;
535*63afb9a5SDavid du Colombier 	}
536*63afb9a5SDavid du Colombier 	if(strcmp(f[0], "tcp") != 0 && strcmp(f[0], "net") != 0){
537*63afb9a5SDavid du Colombier 		free(s);
538*63afb9a5SDavid du Colombier 		respond(r, "unknown protocol");
539*63afb9a5SDavid du Colombier 		return;
540*63afb9a5SDavid du Colombier 	}
541*63afb9a5SDavid du Colombier 	port = ndbfindport(f[2]);
542*63afb9a5SDavid du Colombier 	if(port <= 0){
543*63afb9a5SDavid du Colombier 		free(s);
544*63afb9a5SDavid du Colombier 		respond(r, "no translation found");
545*63afb9a5SDavid du Colombier 		return;
546*63afb9a5SDavid du Colombier 	}
547*63afb9a5SDavid du Colombier 
548*63afb9a5SDavid du Colombier 	ns = smprint("%s/tcp/clone %s!%d", mtpt, f[1], port);
549*63afb9a5SDavid du Colombier 	if(ns == nil){
550*63afb9a5SDavid du Colombier 		free(s);
551*63afb9a5SDavid du Colombier 		rerrstr(err, sizeof err);
552*63afb9a5SDavid du Colombier 		respond(r, err);
553*63afb9a5SDavid du Colombier 		return;
554*63afb9a5SDavid du Colombier 	}
555*63afb9a5SDavid du Colombier 	free(s);
556*63afb9a5SDavid du Colombier 	free(cs->resp);
557*63afb9a5SDavid du Colombier 	cs->resp = ns;
558*63afb9a5SDavid du Colombier 	cs->isnew = 1;
559*63afb9a5SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
560*63afb9a5SDavid du Colombier 	respond(r, nil);
561*63afb9a5SDavid du Colombier }
562*63afb9a5SDavid du Colombier 
563*63afb9a5SDavid du Colombier static void
ctlread(Req * r,Client * c)564*63afb9a5SDavid du Colombier ctlread(Req *r, Client *c)
565*63afb9a5SDavid du Colombier {
566*63afb9a5SDavid du Colombier 	char buf[32];
567*63afb9a5SDavid du Colombier 
568*63afb9a5SDavid du Colombier 	sprint(buf, "%d", c->num);
569*63afb9a5SDavid du Colombier 	readstr(r, buf);
570*63afb9a5SDavid du Colombier 	respond(r, nil);
571*63afb9a5SDavid du Colombier }
572*63afb9a5SDavid du Colombier 
573*63afb9a5SDavid du Colombier static void
ctlwrite(Req * r,Client * c)574*63afb9a5SDavid du Colombier ctlwrite(Req *r, Client *c)
575*63afb9a5SDavid du Colombier {
576*63afb9a5SDavid du Colombier 	char *f[3], *s;
577*63afb9a5SDavid du Colombier 	int nf;
578*63afb9a5SDavid du Colombier 	Msg *m;
579*63afb9a5SDavid du Colombier 
580*63afb9a5SDavid du Colombier 	s = emalloc(r->ifcall.count+1);
581*63afb9a5SDavid du Colombier 	memmove(s, r->ifcall.data, r->ifcall.count);
582*63afb9a5SDavid du Colombier 	s[r->ifcall.count] = '\0';
583*63afb9a5SDavid du Colombier 
584*63afb9a5SDavid du Colombier 	nf = tokenize(s, f, 3);
585*63afb9a5SDavid du Colombier 	if(nf == 0){
586*63afb9a5SDavid du Colombier 		free(s);
587*63afb9a5SDavid du Colombier 		respond(r, nil);
588*63afb9a5SDavid du Colombier 		return;
589*63afb9a5SDavid du Colombier 	}
590*63afb9a5SDavid du Colombier 
591*63afb9a5SDavid du Colombier 	if(strcmp(f[0], "hangup") == 0){
592*63afb9a5SDavid du Colombier 		if(c->state != Established)
593*63afb9a5SDavid du Colombier 			goto Badarg;
594*63afb9a5SDavid du Colombier 		if(nf != 1)
595*63afb9a5SDavid du Colombier 			goto Badarg;
596*63afb9a5SDavid du Colombier 		queuereq(c, r);
597*63afb9a5SDavid du Colombier 		teardownclient(c);
598*63afb9a5SDavid du Colombier 	}else if(strcmp(f[0], "connect") == 0){
599*63afb9a5SDavid du Colombier 		if(c->state != Closed)
600*63afb9a5SDavid du Colombier 			goto Badarg;
601*63afb9a5SDavid du Colombier 		if(nf != 2)
602*63afb9a5SDavid du Colombier 			goto Badarg;
603*63afb9a5SDavid du Colombier 		c->connect = estrdup9p(f[1]);
604*63afb9a5SDavid du Colombier 		nf = getfields(f[1], f, nelem(f), 0, "!");
605*63afb9a5SDavid du Colombier 		if(nf != 2){
606*63afb9a5SDavid du Colombier 			free(c->connect);
607*63afb9a5SDavid du Colombier 			c->connect = nil;
608*63afb9a5SDavid du Colombier 			goto Badarg;
609*63afb9a5SDavid du Colombier 		}
610*63afb9a5SDavid du Colombier 		c->state = Dialing;
611*63afb9a5SDavid du Colombier 		m = allocmsg(conn, SSH_MSG_PORT_OPEN, 4+4+strlen(f[0])+4+4+strlen("localhost"));
612*63afb9a5SDavid du Colombier 		putlong(m, c->num);
613*63afb9a5SDavid du Colombier 		putstring(m, f[0]);
614*63afb9a5SDavid du Colombier 		putlong(m, ndbfindport(f[1]));
615*63afb9a5SDavid du Colombier 		putstring(m, "localhost");
616*63afb9a5SDavid du Colombier 		queuereq(c, r);
617*63afb9a5SDavid du Colombier 		sendmsg(m);
618*63afb9a5SDavid du Colombier 	}else{
619*63afb9a5SDavid du Colombier 	Badarg:
620*63afb9a5SDavid du Colombier 		respond(r, "bad or inappropriate tcp control message");
621*63afb9a5SDavid du Colombier 	}
622*63afb9a5SDavid du Colombier 	free(s);
623*63afb9a5SDavid du Colombier }
624*63afb9a5SDavid du Colombier 
625*63afb9a5SDavid du Colombier static void
dataread(Req * r,Client * c)626*63afb9a5SDavid du Colombier dataread(Req *r, Client *c)
627*63afb9a5SDavid du Colombier {
628*63afb9a5SDavid du Colombier 	if(c->state != Established){
629*63afb9a5SDavid du Colombier 		respond(r, "not connected");
630*63afb9a5SDavid du Colombier 		return;
631*63afb9a5SDavid du Colombier 	}
632*63afb9a5SDavid du Colombier 	queuereq(c, r);
633*63afb9a5SDavid du Colombier 	matchmsgs(c);
634*63afb9a5SDavid du Colombier }
635*63afb9a5SDavid du Colombier 
636*63afb9a5SDavid du Colombier static void
datawrite(Req * r,Client * c)637*63afb9a5SDavid du Colombier datawrite(Req *r, Client *c)
638*63afb9a5SDavid du Colombier {
639*63afb9a5SDavid du Colombier 	Msg *m;
640*63afb9a5SDavid du Colombier 
641*63afb9a5SDavid du Colombier 	if(c->state != Established){
642*63afb9a5SDavid du Colombier 		respond(r, "not connected");
643*63afb9a5SDavid du Colombier 		return;
644*63afb9a5SDavid du Colombier 	}
645*63afb9a5SDavid du Colombier 	if(r->ifcall.count){
646*63afb9a5SDavid du Colombier 		m = allocmsg(conn, SSH_MSG_CHANNEL_DATA, 4+4+r->ifcall.count);
647*63afb9a5SDavid du Colombier 		putlong(m, c->servernum);
648*63afb9a5SDavid du Colombier 		putlong(m, r->ifcall.count);
649*63afb9a5SDavid du Colombier 		putbytes(m, r->ifcall.data, r->ifcall.count);
650*63afb9a5SDavid du Colombier 		sendmsg(m);
651*63afb9a5SDavid du Colombier 	}
652*63afb9a5SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
653*63afb9a5SDavid du Colombier 	respond(r, nil);
654*63afb9a5SDavid du Colombier }
655*63afb9a5SDavid du Colombier 
656*63afb9a5SDavid du Colombier static void
localread(Req * r)657*63afb9a5SDavid du Colombier localread(Req *r)
658*63afb9a5SDavid du Colombier {
659*63afb9a5SDavid du Colombier 	char buf[128];
660*63afb9a5SDavid du Colombier 
661*63afb9a5SDavid du Colombier 	snprint(buf, sizeof buf, "%s!%d\n", remoteip, 0);
662*63afb9a5SDavid du Colombier 	readstr(r, buf);
663*63afb9a5SDavid du Colombier 	respond(r, nil);
664*63afb9a5SDavid du Colombier }
665*63afb9a5SDavid du Colombier 
666*63afb9a5SDavid du Colombier static void
remoteread(Req * r,Client * c)667*63afb9a5SDavid du Colombier remoteread(Req *r, Client *c)
668*63afb9a5SDavid du Colombier {
669*63afb9a5SDavid du Colombier 	char *s;
670*63afb9a5SDavid du Colombier 	char buf[128];
671*63afb9a5SDavid du Colombier 
672*63afb9a5SDavid du Colombier 	s = c->connect;
673*63afb9a5SDavid du Colombier 	if(s == nil)
674*63afb9a5SDavid du Colombier 		s = "::!0";
675*63afb9a5SDavid du Colombier 	snprint(buf, sizeof buf, "%s\n", s);
676*63afb9a5SDavid du Colombier 	readstr(r, buf);
677*63afb9a5SDavid du Colombier 	respond(r, nil);
678*63afb9a5SDavid du Colombier }
679*63afb9a5SDavid du Colombier 
680*63afb9a5SDavid du Colombier static void
statusread(Req * r,Client * c)681*63afb9a5SDavid du Colombier statusread(Req *r, Client *c)
682*63afb9a5SDavid du Colombier {
683*63afb9a5SDavid du Colombier 	char buf[64];
684*63afb9a5SDavid du Colombier 	char *s;
685*63afb9a5SDavid du Colombier 
686*63afb9a5SDavid du Colombier 	snprint(buf, sizeof buf, "%s!%d", remoteip, 0);
687*63afb9a5SDavid du Colombier 	s = statestr[c->state];
688*63afb9a5SDavid du Colombier 	readstr(r, s);
689*63afb9a5SDavid du Colombier 	respond(r, nil);
690*63afb9a5SDavid du Colombier }
691*63afb9a5SDavid du Colombier 
692*63afb9a5SDavid du Colombier static void
fsread(Req * r)693*63afb9a5SDavid du Colombier fsread(Req *r)
694*63afb9a5SDavid du Colombier {
695*63afb9a5SDavid du Colombier 	char e[ERRMAX];
696*63afb9a5SDavid du Colombier 	ulong path;
697*63afb9a5SDavid du Colombier 
698*63afb9a5SDavid du Colombier 	path = r->fid->qid.path;
699*63afb9a5SDavid du Colombier 	switch(TYPE(path)){
700*63afb9a5SDavid du Colombier 	default:
701*63afb9a5SDavid du Colombier 		snprint(e, sizeof e, "bug in fsread path=%lux", path);
702*63afb9a5SDavid du Colombier 		respond(r, e);
703*63afb9a5SDavid du Colombier 		break;
704*63afb9a5SDavid du Colombier 
705*63afb9a5SDavid du Colombier 	case Qroot:
706*63afb9a5SDavid du Colombier 		dirread9p(r, rootgen, nil);
707*63afb9a5SDavid du Colombier 		respond(r, nil);
708*63afb9a5SDavid du Colombier 		break;
709*63afb9a5SDavid du Colombier 
710*63afb9a5SDavid du Colombier 	case Qcs:
711*63afb9a5SDavid du Colombier 		csread(r);
712*63afb9a5SDavid du Colombier 		break;
713*63afb9a5SDavid du Colombier 
714*63afb9a5SDavid du Colombier 	case Qtcp:
715*63afb9a5SDavid du Colombier 		dirread9p(r, tcpgen, nil);
716*63afb9a5SDavid du Colombier 		respond(r, nil);
717*63afb9a5SDavid du Colombier 		break;
718*63afb9a5SDavid du Colombier 
719*63afb9a5SDavid du Colombier 	case Qn:
720*63afb9a5SDavid du Colombier 		dirread9p(r, clientgen, client[NUM(path)]);
721*63afb9a5SDavid du Colombier 		respond(r, nil);
722*63afb9a5SDavid du Colombier 		break;
723*63afb9a5SDavid du Colombier 
724*63afb9a5SDavid du Colombier 	case Qctl:
725*63afb9a5SDavid du Colombier 		ctlread(r, client[NUM(path)]);
726*63afb9a5SDavid du Colombier 		break;
727*63afb9a5SDavid du Colombier 
728*63afb9a5SDavid du Colombier 	case Qdata:
729*63afb9a5SDavid du Colombier 		dataread(r, client[NUM(path)]);
730*63afb9a5SDavid du Colombier 		break;
731*63afb9a5SDavid du Colombier 
732*63afb9a5SDavid du Colombier 	case Qlocal:
733*63afb9a5SDavid du Colombier 		localread(r);
734*63afb9a5SDavid du Colombier 		break;
735*63afb9a5SDavid du Colombier 
736*63afb9a5SDavid du Colombier 	case Qremote:
737*63afb9a5SDavid du Colombier 		remoteread(r, client[NUM(path)]);
738*63afb9a5SDavid du Colombier 		break;
739*63afb9a5SDavid du Colombier 
740*63afb9a5SDavid du Colombier 	case Qstatus:
741*63afb9a5SDavid du Colombier 		statusread(r, client[NUM(path)]);
742*63afb9a5SDavid du Colombier 		break;
743*63afb9a5SDavid du Colombier 	}
744*63afb9a5SDavid du Colombier }
745*63afb9a5SDavid du Colombier 
746*63afb9a5SDavid du Colombier static void
fswrite(Req * r)747*63afb9a5SDavid du Colombier fswrite(Req *r)
748*63afb9a5SDavid du Colombier {
749*63afb9a5SDavid du Colombier 	ulong path;
750*63afb9a5SDavid du Colombier 	char e[ERRMAX];
751*63afb9a5SDavid du Colombier 
752*63afb9a5SDavid du Colombier 	path = r->fid->qid.path;
753*63afb9a5SDavid du Colombier 	switch(TYPE(path)){
754*63afb9a5SDavid du Colombier 	default:
755*63afb9a5SDavid du Colombier 		snprint(e, sizeof e, "bug in fswrite path=%lux", path);
756*63afb9a5SDavid du Colombier 		respond(r, e);
757*63afb9a5SDavid du Colombier 		break;
758*63afb9a5SDavid du Colombier 
759*63afb9a5SDavid du Colombier 	case Qcs:
760*63afb9a5SDavid du Colombier 		cswrite(r);
761*63afb9a5SDavid du Colombier 		break;
762*63afb9a5SDavid du Colombier 
763*63afb9a5SDavid du Colombier 	case Qctl:
764*63afb9a5SDavid du Colombier 		ctlwrite(r, client[NUM(path)]);
765*63afb9a5SDavid du Colombier 		break;
766*63afb9a5SDavid du Colombier 
767*63afb9a5SDavid du Colombier 	case Qdata:
768*63afb9a5SDavid du Colombier 		datawrite(r, client[NUM(path)]);
769*63afb9a5SDavid du Colombier 		break;
770*63afb9a5SDavid du Colombier 	}
771*63afb9a5SDavid du Colombier }
772*63afb9a5SDavid du Colombier 
773*63afb9a5SDavid du Colombier static void
fsopen(Req * r)774*63afb9a5SDavid du Colombier fsopen(Req *r)
775*63afb9a5SDavid du Colombier {
776*63afb9a5SDavid du Colombier 	static int need[4] = { 4, 2, 6, 1 };
777*63afb9a5SDavid du Colombier 	ulong path;
778*63afb9a5SDavid du Colombier 	int n;
779*63afb9a5SDavid du Colombier 	Tab *t;
780*63afb9a5SDavid du Colombier 	Cs *cs;
781*63afb9a5SDavid du Colombier 
782*63afb9a5SDavid du Colombier 	/*
783*63afb9a5SDavid du Colombier 	 * lib9p already handles the blatantly obvious.
784*63afb9a5SDavid du Colombier 	 * we just have to enforce the permissions we have set.
785*63afb9a5SDavid du Colombier 	 */
786*63afb9a5SDavid du Colombier 	path = r->fid->qid.path;
787*63afb9a5SDavid du Colombier 	t = &tab[TYPE(path)];
788*63afb9a5SDavid du Colombier 	n = need[r->ifcall.mode&3];
789*63afb9a5SDavid du Colombier 	if((n&t->mode) != n){
790*63afb9a5SDavid du Colombier 		respond(r, "permission denied");
791*63afb9a5SDavid du Colombier 		return;
792*63afb9a5SDavid du Colombier 	}
793*63afb9a5SDavid du Colombier 
794*63afb9a5SDavid du Colombier 	switch(TYPE(path)){
795*63afb9a5SDavid du Colombier 	case Qcs:
796*63afb9a5SDavid du Colombier 		cs = emalloc(sizeof(Cs));
797*63afb9a5SDavid du Colombier 		r->fid->aux = cs;
798*63afb9a5SDavid du Colombier 		respond(r, nil);
799*63afb9a5SDavid du Colombier 		break;
800*63afb9a5SDavid du Colombier 	case Qclone:
801*63afb9a5SDavid du Colombier 		n = newclient();
802*63afb9a5SDavid du Colombier 		path = PATH(Qctl, n);
803*63afb9a5SDavid du Colombier 		r->fid->qid.path = path;
804*63afb9a5SDavid du Colombier 		r->ofcall.qid.path = path;
805*63afb9a5SDavid du Colombier 		if(chatty9p)
806*63afb9a5SDavid du Colombier 			fprint(2, "open clone => path=%lux\n", path);
807*63afb9a5SDavid du Colombier 		t = &tab[Qctl];
808*63afb9a5SDavid du Colombier 		/* fall through */
809*63afb9a5SDavid du Colombier 	default:
810*63afb9a5SDavid du Colombier 		if(t-tab >= Qn)
811*63afb9a5SDavid du Colombier 			client[NUM(path)]->ref++;
812*63afb9a5SDavid du Colombier 		respond(r, nil);
813*63afb9a5SDavid du Colombier 		break;
814*63afb9a5SDavid du Colombier 	}
815*63afb9a5SDavid du Colombier }
816*63afb9a5SDavid du Colombier 
817*63afb9a5SDavid du Colombier static void
fsflush(Req * r)818*63afb9a5SDavid du Colombier fsflush(Req *r)
819*63afb9a5SDavid du Colombier {
820*63afb9a5SDavid du Colombier 	int i;
821*63afb9a5SDavid du Colombier 
822*63afb9a5SDavid du Colombier 	for(i=0; i<nclient; i++)
823*63afb9a5SDavid du Colombier 		if(findreq(client[i], r->oldreq))
824*63afb9a5SDavid du Colombier 			respond(r->oldreq, "interrupted");
825*63afb9a5SDavid du Colombier 	respond(r, nil);
826*63afb9a5SDavid du Colombier }
827*63afb9a5SDavid du Colombier 
828*63afb9a5SDavid du Colombier static void
handlemsg(Msg * m)829*63afb9a5SDavid du Colombier handlemsg(Msg *m)
830*63afb9a5SDavid du Colombier {
831*63afb9a5SDavid du Colombier 	int chan, n;
832*63afb9a5SDavid du Colombier 	Client *c;
833*63afb9a5SDavid du Colombier 
834*63afb9a5SDavid du Colombier 	switch(m->type){
835*63afb9a5SDavid du Colombier 	case SSH_MSG_DISCONNECT:
836*63afb9a5SDavid du Colombier 	case SSH_CMSG_EXIT_CONFIRMATION:
837*63afb9a5SDavid du Colombier 		sysfatal("disconnect");
838*63afb9a5SDavid du Colombier 
839*63afb9a5SDavid du Colombier 	case SSH_CMSG_STDIN_DATA:
840*63afb9a5SDavid du Colombier 	case SSH_CMSG_EOF:
841*63afb9a5SDavid du Colombier 	case SSH_CMSG_WINDOW_SIZE:
842*63afb9a5SDavid du Colombier 		/* don't care */
843*63afb9a5SDavid du Colombier 		free(m);
844*63afb9a5SDavid du Colombier 		break;
845*63afb9a5SDavid du Colombier 
846*63afb9a5SDavid du Colombier 	case SSH_MSG_CHANNEL_DATA:
847*63afb9a5SDavid du Colombier 		chan = getlong(m);
848*63afb9a5SDavid du Colombier 		n = getlong(m);
849*63afb9a5SDavid du Colombier 		if(m->rp+n != m->ep)
850*63afb9a5SDavid du Colombier 			sysfatal("got bad channel data");
851*63afb9a5SDavid du Colombier 		if(chan<nclient && (c=client[chan])->state==Established){
852*63afb9a5SDavid du Colombier 			queuemsg(c, m);
853*63afb9a5SDavid du Colombier 			matchmsgs(c);
854*63afb9a5SDavid du Colombier 		}else
855*63afb9a5SDavid du Colombier 			free(m);
856*63afb9a5SDavid du Colombier 		break;
857*63afb9a5SDavid du Colombier 
858*63afb9a5SDavid du Colombier 	case SSH_MSG_CHANNEL_INPUT_EOF:
859*63afb9a5SDavid du Colombier 		chan = getlong(m);
860*63afb9a5SDavid du Colombier 		free(m);
861*63afb9a5SDavid du Colombier 		if(chan<nclient){
862*63afb9a5SDavid du Colombier 			c = client[chan];
863*63afb9a5SDavid du Colombier 			chan = c->servernum;
864*63afb9a5SDavid du Colombier 			hangupclient(c);
865*63afb9a5SDavid du Colombier 			m = allocmsg(conn, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
866*63afb9a5SDavid du Colombier 			putlong(m, chan);
867*63afb9a5SDavid du Colombier 			sendmsg(m);
868*63afb9a5SDavid du Colombier 		}
869*63afb9a5SDavid du Colombier 		break;
870*63afb9a5SDavid du Colombier 
871*63afb9a5SDavid du Colombier 	case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
872*63afb9a5SDavid du Colombier 		chan = getlong(m);
873*63afb9a5SDavid du Colombier 		if(chan<nclient)
874*63afb9a5SDavid du Colombier 			hangupclient(client[chan]);
875*63afb9a5SDavid du Colombier 		free(m);
876*63afb9a5SDavid du Colombier 		break;
877*63afb9a5SDavid du Colombier 
878*63afb9a5SDavid du Colombier 	case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
879*63afb9a5SDavid du Colombier 		chan = getlong(m);
880*63afb9a5SDavid du Colombier 		c = nil;
881*63afb9a5SDavid du Colombier 		if(chan>=nclient || (c=client[chan])->state != Dialing){
882*63afb9a5SDavid du Colombier 			if(c)
883*63afb9a5SDavid du Colombier 				fprint(2, "cstate %d\n", c->state);
884*63afb9a5SDavid du Colombier 			sysfatal("got unexpected open confirmation for %d", chan);
885*63afb9a5SDavid du Colombier 		}
886*63afb9a5SDavid du Colombier 		c->servernum = getlong(m);
887*63afb9a5SDavid du Colombier 		c->state = Established;
888*63afb9a5SDavid du Colombier 		dialedclient(c);
889*63afb9a5SDavid du Colombier 		free(m);
890*63afb9a5SDavid du Colombier 		break;
891*63afb9a5SDavid du Colombier 
892*63afb9a5SDavid du Colombier 	case SSH_MSG_CHANNEL_OPEN_FAILURE:
893*63afb9a5SDavid du Colombier 		chan = getlong(m);
894*63afb9a5SDavid du Colombier 		c = nil;
895*63afb9a5SDavid du Colombier 		if(chan>=nclient || (c=client[chan])->state != Dialing)
896*63afb9a5SDavid du Colombier 			sysfatal("got unexpected open failure");
897*63afb9a5SDavid du Colombier 		if(m->rp+4 <= m->ep)
898*63afb9a5SDavid du Colombier 			c->servernum = getlong(m);
899*63afb9a5SDavid du Colombier 		c->state = Closed;
900*63afb9a5SDavid du Colombier 		dialedclient(c);
901*63afb9a5SDavid du Colombier 		free(m);
902*63afb9a5SDavid du Colombier 		break;
903*63afb9a5SDavid du Colombier 	}
904*63afb9a5SDavid du Colombier }
905*63afb9a5SDavid du Colombier 
906*63afb9a5SDavid du Colombier void
fsnetproc(void *)907*63afb9a5SDavid du Colombier fsnetproc(void*)
908*63afb9a5SDavid du Colombier {
909*63afb9a5SDavid du Colombier 	ulong path;
910*63afb9a5SDavid du Colombier 	Alt a[4];
911*63afb9a5SDavid du Colombier 	Cs *cs;
912*63afb9a5SDavid du Colombier 	Fid *fid;
913*63afb9a5SDavid du Colombier 	Req *r;
914*63afb9a5SDavid du Colombier 	Msg *m;
915*63afb9a5SDavid du Colombier 
916*63afb9a5SDavid du Colombier 	threadsetname("fsthread");
917*63afb9a5SDavid du Colombier 
918*63afb9a5SDavid du Colombier 	a[0].op = CHANRCV;
919*63afb9a5SDavid du Colombier 	a[0].c = fsclunkchan;
920*63afb9a5SDavid du Colombier 	a[0].v = &fid;
921*63afb9a5SDavid du Colombier 	a[1].op = CHANRCV;
922*63afb9a5SDavid du Colombier 	a[1].c = fsreqchan;
923*63afb9a5SDavid du Colombier 	a[1].v = &r;
924*63afb9a5SDavid du Colombier 	a[2].op = CHANRCV;
925*63afb9a5SDavid du Colombier 	a[2].c = sshmsgchan;
926*63afb9a5SDavid du Colombier 	a[2].v = &m;
927*63afb9a5SDavid du Colombier 	a[3].op = CHANEND;
928*63afb9a5SDavid du Colombier 
929*63afb9a5SDavid du Colombier 	for(;;){
930*63afb9a5SDavid du Colombier 		switch(alt(a)){
931*63afb9a5SDavid du Colombier 		case 0:
932*63afb9a5SDavid du Colombier 			path = fid->qid.path;
933*63afb9a5SDavid du Colombier 			switch(TYPE(path)){
934*63afb9a5SDavid du Colombier 			case Qcs:
935*63afb9a5SDavid du Colombier 				cs = fid->aux;
936*63afb9a5SDavid du Colombier 				if(cs){
937*63afb9a5SDavid du Colombier 					free(cs->resp);
938*63afb9a5SDavid du Colombier 					free(cs);
939*63afb9a5SDavid du Colombier 				}
940*63afb9a5SDavid du Colombier 				break;
941*63afb9a5SDavid du Colombier 			}
942*63afb9a5SDavid du Colombier 			if(fid->omode != -1 && TYPE(path) >= Qn)
943*63afb9a5SDavid du Colombier 				closeclient(client[NUM(path)]);
944*63afb9a5SDavid du Colombier 			sendp(fsclunkwaitchan, nil);
945*63afb9a5SDavid du Colombier 			break;
946*63afb9a5SDavid du Colombier 		case 1:
947*63afb9a5SDavid du Colombier 			switch(r->ifcall.type){
948*63afb9a5SDavid du Colombier 			case Tattach:
949*63afb9a5SDavid du Colombier 				fsattach(r);
950*63afb9a5SDavid du Colombier 				break;
951*63afb9a5SDavid du Colombier 			case Topen:
952*63afb9a5SDavid du Colombier 				fsopen(r);
953*63afb9a5SDavid du Colombier 				break;
954*63afb9a5SDavid du Colombier 			case Tread:
955*63afb9a5SDavid du Colombier 				fsread(r);
956*63afb9a5SDavid du Colombier 				break;
957*63afb9a5SDavid du Colombier 			case Twrite:
958*63afb9a5SDavid du Colombier 				fswrite(r);
959*63afb9a5SDavid du Colombier 				break;
960*63afb9a5SDavid du Colombier 			case Tstat:
961*63afb9a5SDavid du Colombier 				fsstat(r);
962*63afb9a5SDavid du Colombier 				break;
963*63afb9a5SDavid du Colombier 			case Tflush:
964*63afb9a5SDavid du Colombier 				fsflush(r);
965*63afb9a5SDavid du Colombier 				break;
966*63afb9a5SDavid du Colombier 			default:
967*63afb9a5SDavid du Colombier 				respond(r, "bug in fsthread");
968*63afb9a5SDavid du Colombier 				break;
969*63afb9a5SDavid du Colombier 			}
970*63afb9a5SDavid du Colombier 			sendp(fsreqwaitchan, 0);
971*63afb9a5SDavid du Colombier 			break;
972*63afb9a5SDavid du Colombier 		case 2:
973*63afb9a5SDavid du Colombier 			handlemsg(m);
974*63afb9a5SDavid du Colombier 			break;
975*63afb9a5SDavid du Colombier 		}
976*63afb9a5SDavid du Colombier 	}
977*63afb9a5SDavid du Colombier }
978*63afb9a5SDavid du Colombier 
979*63afb9a5SDavid du Colombier static void
fssend(Req * r)980*63afb9a5SDavid du Colombier fssend(Req *r)
981*63afb9a5SDavid du Colombier {
982*63afb9a5SDavid du Colombier 	sendp(fsreqchan, r);
983*63afb9a5SDavid du Colombier 	recvp(fsreqwaitchan);	/* avoids need to deal with spurious flushes */
984*63afb9a5SDavid du Colombier }
985*63afb9a5SDavid du Colombier 
986*63afb9a5SDavid du Colombier static void
fsdestroyfid(Fid * fid)987*63afb9a5SDavid du Colombier fsdestroyfid(Fid *fid)
988*63afb9a5SDavid du Colombier {
989*63afb9a5SDavid du Colombier 	sendp(fsclunkchan, fid);
990*63afb9a5SDavid du Colombier 	recvp(fsclunkwaitchan);
991*63afb9a5SDavid du Colombier }
992*63afb9a5SDavid du Colombier 
993*63afb9a5SDavid du Colombier void
takedown(Srv *)994*63afb9a5SDavid du Colombier takedown(Srv*)
995*63afb9a5SDavid du Colombier {
996*63afb9a5SDavid du Colombier 	threadexitsall("done");
997*63afb9a5SDavid du Colombier }
998*63afb9a5SDavid du Colombier 
999*63afb9a5SDavid du Colombier Srv fs =
1000*63afb9a5SDavid du Colombier {
1001*63afb9a5SDavid du Colombier .attach=		fssend,
1002*63afb9a5SDavid du Colombier .destroyfid=	fsdestroyfid,
1003*63afb9a5SDavid du Colombier .walk1=		fswalk1,
1004*63afb9a5SDavid du Colombier .open=		fssend,
1005*63afb9a5SDavid du Colombier .read=		fssend,
1006*63afb9a5SDavid du Colombier .write=		fssend,
1007*63afb9a5SDavid du Colombier .stat=		fssend,
1008*63afb9a5SDavid du Colombier .flush=		fssend,
1009*63afb9a5SDavid du Colombier .end=		takedown,
1010*63afb9a5SDavid du Colombier };
1011*63afb9a5SDavid du Colombier 
1012*63afb9a5SDavid du Colombier void
threadmain(int argc,char ** argv)1013*63afb9a5SDavid du Colombier threadmain(int argc, char **argv)
1014*63afb9a5SDavid du Colombier {
1015*63afb9a5SDavid du Colombier 	int i, fd;
1016*63afb9a5SDavid du Colombier 	char *host, *user, *p, *service;
1017*63afb9a5SDavid du Colombier 	char *f[16];
1018*63afb9a5SDavid du Colombier 	Msg *m;
1019*63afb9a5SDavid du Colombier 	static Conn c;
1020*63afb9a5SDavid du Colombier 
1021*63afb9a5SDavid du Colombier 	fmtinstall('B', mpfmt);
1022*63afb9a5SDavid du Colombier 	fmtinstall('H', encodefmt);
1023*63afb9a5SDavid du Colombier 
1024*63afb9a5SDavid du Colombier 	mtpt = "/net";
1025*63afb9a5SDavid du Colombier 	service = nil;
1026*63afb9a5SDavid du Colombier 	user = nil;
1027*63afb9a5SDavid du Colombier 	ARGBEGIN{
1028*63afb9a5SDavid du Colombier 	case 'B':	/* undocumented, debugging */
1029*63afb9a5SDavid du Colombier 		doabort = 1;
1030*63afb9a5SDavid du Colombier 		break;
1031*63afb9a5SDavid du Colombier 	case 'D':	/* undocumented, debugging */
1032*63afb9a5SDavid du Colombier 		debuglevel = strtol(EARGF(usage()), nil, 0);
1033*63afb9a5SDavid du Colombier 		break;
1034*63afb9a5SDavid du Colombier 	case '9':	/* undocumented, debugging */
1035*63afb9a5SDavid du Colombier 		chatty9p++;
1036*63afb9a5SDavid du Colombier 		break;
1037*63afb9a5SDavid du Colombier 
1038*63afb9a5SDavid du Colombier 	case 'A':
1039*63afb9a5SDavid du Colombier 		authlist = EARGF(usage());
1040*63afb9a5SDavid du Colombier 		break;
1041*63afb9a5SDavid du Colombier 	case 'c':
1042*63afb9a5SDavid du Colombier 		cipherlist = EARGF(usage());
1043*63afb9a5SDavid du Colombier 		break;
1044*63afb9a5SDavid du Colombier 	case 'm':
1045*63afb9a5SDavid du Colombier 		mtpt = EARGF(usage());
1046*63afb9a5SDavid du Colombier 		break;
1047*63afb9a5SDavid du Colombier 	case 's':
1048*63afb9a5SDavid du Colombier 		service = EARGF(usage());
1049*63afb9a5SDavid du Colombier 		break;
1050*63afb9a5SDavid du Colombier 	default:
1051*63afb9a5SDavid du Colombier 		usage();
1052*63afb9a5SDavid du Colombier 	}ARGEND
1053*63afb9a5SDavid du Colombier 
1054*63afb9a5SDavid du Colombier 	if(argc != 1)
1055*63afb9a5SDavid du Colombier 		usage();
1056*63afb9a5SDavid du Colombier 
1057*63afb9a5SDavid du Colombier 	host = argv[0];
1058*63afb9a5SDavid du Colombier 
1059*63afb9a5SDavid du Colombier 	if((p = strchr(host, '@')) != nil){
1060*63afb9a5SDavid du Colombier 		*p++ = '\0';
1061*63afb9a5SDavid du Colombier 		user = host;
1062*63afb9a5SDavid du Colombier 		host = p;
1063*63afb9a5SDavid du Colombier 	}
1064*63afb9a5SDavid du Colombier 	if(user == nil)
1065*63afb9a5SDavid du Colombier 		user = getenv("user");
1066*63afb9a5SDavid du Colombier 	if(user == nil)
1067*63afb9a5SDavid du Colombier 		sysfatal("cannot find user name");
1068*63afb9a5SDavid du Colombier 
1069*63afb9a5SDavid du Colombier 	privatefactotum();
1070*63afb9a5SDavid du Colombier 
1071*63afb9a5SDavid du Colombier 	if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
1072*63afb9a5SDavid du Colombier 		sysfatal("dialing %s: %r", host);
1073*63afb9a5SDavid du Colombier 
1074*63afb9a5SDavid du Colombier 	c.interactive = isatty(0);
1075*63afb9a5SDavid du Colombier 	c.fd[0] = c.fd[1] = fd;
1076*63afb9a5SDavid du Colombier 	c.user = user;
1077*63afb9a5SDavid du Colombier 	c.host = host;
1078*63afb9a5SDavid du Colombier 	setaliases(&c, host);
1079*63afb9a5SDavid du Colombier 
1080*63afb9a5SDavid du Colombier 	c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
1081*63afb9a5SDavid du Colombier 	c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
1082*63afb9a5SDavid du Colombier 	for(i=0; i<c.nokcipher; i++)
1083*63afb9a5SDavid du Colombier 		c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
1084*63afb9a5SDavid du Colombier 
1085*63afb9a5SDavid du Colombier 	c.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
1086*63afb9a5SDavid du Colombier 	c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
1087*63afb9a5SDavid du Colombier 	for(i=0; i<c.nokauth; i++)
1088*63afb9a5SDavid du Colombier 		c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
1089*63afb9a5SDavid du Colombier 
1090*63afb9a5SDavid du Colombier 	sshclienthandshake(&c);
1091*63afb9a5SDavid du Colombier 
1092*63afb9a5SDavid du Colombier 	requestpty(&c);		/* turns on TCP_NODELAY on other side */
1093*63afb9a5SDavid du Colombier 	m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
1094*63afb9a5SDavid du Colombier 	sendmsg(m);
1095*63afb9a5SDavid du Colombier 
1096*63afb9a5SDavid du Colombier 	time0 = time(0);
1097*63afb9a5SDavid du Colombier 	sshmsgchan = chancreate(sizeof(Msg*), 16);
1098*63afb9a5SDavid du Colombier 	fsreqchan = chancreate(sizeof(Req*), 0);
1099*63afb9a5SDavid du Colombier 	fsreqwaitchan = chancreate(sizeof(void*), 0);
1100*63afb9a5SDavid du Colombier 	fsclunkchan = chancreate(sizeof(Fid*), 0);
1101*63afb9a5SDavid du Colombier 	fsclunkwaitchan = chancreate(sizeof(void*), 0);
1102*63afb9a5SDavid du Colombier 
1103*63afb9a5SDavid du Colombier 	conn = &c;
1104*63afb9a5SDavid du Colombier 	procrfork(sshreadproc, &c, 8192, RFNAMEG|RFNOTEG);
1105*63afb9a5SDavid du Colombier 	procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG);
1106*63afb9a5SDavid du Colombier 
1107*63afb9a5SDavid du Colombier 	threadpostmountsrv(&fs, service, mtpt, MREPL);
1108*63afb9a5SDavid du Colombier 	exits(0);
1109*63afb9a5SDavid du Colombier }
1110*63afb9a5SDavid du Colombier 
1111