sshnet.c 17 KB

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