sshnet.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  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. respond(r->oldreq, "interrupted");
  719. respond(r, nil);
  720. }
  721. static void
  722. handlemsg(Msg *m)
  723. {
  724. int chan, n;
  725. Client *c;
  726. switch(m->type){
  727. case SSH_MSG_DISCONNECT:
  728. case SSH_CMSG_EXIT_CONFIRMATION:
  729. sysfatal("disconnect");
  730. case SSH_CMSG_STDIN_DATA:
  731. case SSH_CMSG_EOF:
  732. case SSH_CMSG_WINDOW_SIZE:
  733. /* don't care */
  734. free(m);
  735. break;
  736. case SSH_MSG_CHANNEL_DATA:
  737. chan = getlong(m);
  738. n = getlong(m);
  739. if(m->rp+n != m->ep)
  740. sysfatal("got bad channel data");
  741. if(chan<nclient && (c=client[chan])->state==Established){
  742. queuemsg(c, m);
  743. matchmsgs(c);
  744. }else
  745. free(m);
  746. break;
  747. case SSH_MSG_CHANNEL_INPUT_EOF:
  748. chan = getlong(m);
  749. free(m);
  750. if(chan<nclient){
  751. c = client[chan];
  752. chan = c->servernum;
  753. hangupclient(c);
  754. m = allocmsg(conn, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  755. putlong(m, chan);
  756. sendmsg(m);
  757. }
  758. break;
  759. case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
  760. chan = getlong(m);
  761. if(chan<nclient)
  762. hangupclient(client[chan]);
  763. free(m);
  764. break;
  765. case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
  766. chan = getlong(m);
  767. c = nil;
  768. if(chan>=nclient || (c=client[chan])->state != Dialing){
  769. if(c)
  770. fprint(2, "cstate %d\n", c->state);
  771. sysfatal("got unexpected open confirmation for %d", chan);
  772. }
  773. c->servernum = getlong(m);
  774. c->state = Established;
  775. dialedclient(c);
  776. free(m);
  777. break;
  778. case SSH_MSG_CHANNEL_OPEN_FAILURE:
  779. chan = getlong(m);
  780. c = nil;
  781. if(chan>=nclient || (c=client[chan])->state != Dialing)
  782. sysfatal("got unexpected open failure");
  783. if(m->rp+4 <= m->ep)
  784. c->servernum = getlong(m);
  785. c->state = Closed;
  786. dialedclient(c);
  787. free(m);
  788. break;
  789. }
  790. }
  791. void
  792. fsnetproc(void*)
  793. {
  794. ulong path;
  795. Alt a[4];
  796. Cs *cs;
  797. Fid *fid;
  798. Req *r;
  799. Msg *m;
  800. threadsetname("fsthread");
  801. a[0].op = CHANRCV;
  802. a[0].c = fsclunkchan;
  803. a[0].v = &fid;
  804. a[1].op = CHANRCV;
  805. a[1].c = fsreqchan;
  806. a[1].v = &r;
  807. a[2].op = CHANRCV;
  808. a[2].c = sshmsgchan;
  809. a[2].v = &m;
  810. a[3].op = CHANEND;
  811. for(;;){
  812. switch(alt(a)){
  813. case 0:
  814. path = fid->qid.path;
  815. switch(TYPE(path)){
  816. case Qcs:
  817. cs = fid->aux;
  818. if(cs){
  819. free(cs->resp);
  820. free(cs);
  821. }
  822. break;
  823. }
  824. if(fid->omode != -1 && TYPE(path) >= Qn)
  825. closeclient(client[NUM(path)]);
  826. sendp(fsclunkwaitchan, nil);
  827. break;
  828. case 1:
  829. switch(r->ifcall.type){
  830. case Tattach:
  831. fsattach(r);
  832. break;
  833. case Topen:
  834. fsopen(r);
  835. break;
  836. case Tread:
  837. fsread(r);
  838. break;
  839. case Twrite:
  840. fswrite(r);
  841. break;
  842. case Tstat:
  843. fsstat(r);
  844. break;
  845. case Tflush:
  846. fsflush(r);
  847. break;
  848. default:
  849. respond(r, "bug in fsthread");
  850. break;
  851. }
  852. sendp(fsreqwaitchan, 0);
  853. break;
  854. case 2:
  855. handlemsg(m);
  856. break;
  857. }
  858. }
  859. }
  860. static void
  861. fssend(Req *r)
  862. {
  863. sendp(fsreqchan, r);
  864. recvp(fsreqwaitchan); /* avoids need to deal with spurious flushes */
  865. }
  866. static void
  867. fsdestroyfid(Fid *fid)
  868. {
  869. sendp(fsclunkchan, fid);
  870. recvp(fsclunkwaitchan);
  871. }
  872. void
  873. takedown(Srv*)
  874. {
  875. threadexitsall("done");
  876. }
  877. Srv fs =
  878. {
  879. .attach= fssend,
  880. .destroyfid= fsdestroyfid,
  881. .walk1= fswalk1,
  882. .open= fssend,
  883. .read= fssend,
  884. .write= fssend,
  885. .stat= fssend,
  886. .flush= fssend,
  887. .end= takedown,
  888. };
  889. void
  890. threadmain(int argc, char **argv)
  891. {
  892. int i, fd;
  893. char *host, *user, *p, *service;
  894. char *f[16];
  895. Msg *m;
  896. static Conn c;
  897. fmtinstall('B', mpfmt);
  898. fmtinstall('H', encodefmt);
  899. mtpt = "/net";
  900. service = nil;
  901. user = nil;
  902. ARGBEGIN{
  903. case 'B': /* undocumented, debugging */
  904. doabort = 1;
  905. break;
  906. case 'D': /* undocumented, debugging */
  907. debuglevel = strtol(EARGF(usage()), nil, 0);
  908. break;
  909. case '9': /* undocumented, debugging */
  910. chatty9p++;
  911. break;
  912. case 'A':
  913. authlist = EARGF(usage());
  914. break;
  915. case 'c':
  916. cipherlist = EARGF(usage());
  917. break;
  918. case 'm':
  919. mtpt = EARGF(usage());
  920. break;
  921. case 's':
  922. service = EARGF(usage());
  923. break;
  924. default:
  925. usage();
  926. }ARGEND
  927. if(argc != 1)
  928. usage();
  929. host = argv[0];
  930. if((p = strchr(host, '@')) != nil){
  931. *p++ = '\0';
  932. user = host;
  933. host = p;
  934. }
  935. if(user == nil)
  936. user = getenv("user");
  937. if(user == nil)
  938. sysfatal("cannot find user name");
  939. privatefactotum();
  940. if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
  941. sysfatal("dialing %s: %r", host);
  942. c.interactive = isatty(0);
  943. c.fd[0] = c.fd[1] = fd;
  944. c.user = user;
  945. c.host = host;
  946. setaliases(&c, host);
  947. c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
  948. c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
  949. for(i=0; i<c.nokcipher; i++)
  950. c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
  951. c.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
  952. c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
  953. for(i=0; i<c.nokauth; i++)
  954. c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
  955. sshclienthandshake(&c);
  956. requestpty(&c); /* turns on TCP_NODELAY on other side */
  957. m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
  958. sendmsg(m);
  959. time0 = time(0);
  960. sshmsgchan = chancreate(sizeof(Msg*), 16);
  961. fsreqchan = chancreate(sizeof(Req*), 0);
  962. fsreqwaitchan = chancreate(sizeof(void*), 0);
  963. fsclunkchan = chancreate(sizeof(Fid*), 0);
  964. fsclunkwaitchan = chancreate(sizeof(void*), 0);
  965. conn = &c;
  966. procrfork(sshreadproc, &c, 8192, RFNAMEG|RFNOTEG);
  967. procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG);
  968. threadpostmountsrv(&fs, service, mtpt, MREPL);
  969. exits(0);
  970. }