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, -1);
  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;
  411. int n;
  412. static Ndb *db;
  413. if(*p == '\0')
  414. return -1;
  415. n = strtol(p, &s, 0);
  416. if(*s == '\0')
  417. return n;
  418. if(db == nil){
  419. db = ndbopen("/lib/ndb/common");
  420. if(db == nil)
  421. return -1;
  422. }
  423. port = ndbgetvalue(db, nil, "tcp", p, "port", nil);
  424. if(port == nil)
  425. return -1;
  426. n = atoi(port);
  427. free(port);
  428. return n;
  429. }
  430. static void
  431. csread(Req *r)
  432. {
  433. Cs *cs;
  434. cs = r->fid->aux;
  435. if(cs->resp==nil){
  436. respond(r, "cs read without write");
  437. return;
  438. }
  439. if(r->ifcall.offset==0){
  440. if(!cs->isnew){
  441. r->ofcall.count = 0;
  442. respond(r, nil);
  443. return;
  444. }
  445. cs->isnew = 0;
  446. }
  447. readstr(r, cs->resp);
  448. respond(r, nil);
  449. }
  450. static void
  451. cswrite(Req *r)
  452. {
  453. int port, nf;
  454. char err[ERRMAX], *f[4], *s, *ns;
  455. Cs *cs;
  456. cs = r->fid->aux;
  457. s = emalloc(r->ifcall.count+1);
  458. memmove(s, r->ifcall.data, r->ifcall.count);
  459. s[r->ifcall.count] = '\0';
  460. nf = getfields(s, f, nelem(f), 0, "!");
  461. if(nf != 3){
  462. free(s);
  463. respond(r, "can't translate");
  464. return;
  465. }
  466. if(strcmp(f[0], "tcp") != 0 && strcmp(f[0], "net") != 0){
  467. free(s);
  468. respond(r, "unknown protocol");
  469. return;
  470. }
  471. port = ndbfindport(f[2]);
  472. if(port <= 0){
  473. free(s);
  474. respond(r, "no translation found");
  475. return;
  476. }
  477. ns = smprint("%s/tcp/clone %s!%d", mtpt, f[1], port);
  478. if(ns == nil){
  479. free(s);
  480. rerrstr(err, sizeof err);
  481. respond(r, err);
  482. return;
  483. }
  484. free(s);
  485. free(cs->resp);
  486. cs->resp = ns;
  487. cs->isnew = 1;
  488. r->ofcall.count = r->ifcall.count;
  489. respond(r, nil);
  490. }
  491. static void
  492. ctlread(Req *r, Client *c)
  493. {
  494. char buf[32];
  495. sprint(buf, "%d", c->num);
  496. readstr(r, buf);
  497. respond(r, nil);
  498. }
  499. static void
  500. ctlwrite(Req *r, Client *c)
  501. {
  502. char *f[3], *s;
  503. int nf;
  504. Msg *m;
  505. s = emalloc(r->ifcall.count+1);
  506. memmove(s, r->ifcall.data, r->ifcall.count);
  507. s[r->ifcall.count] = '\0';
  508. nf = tokenize(s, f, 3);
  509. if(nf == 0){
  510. free(s);
  511. respond(r, nil);
  512. return;
  513. }
  514. if(strcmp(f[0], "hangup") == 0){
  515. if(c->state != Established)
  516. goto Badarg;
  517. if(nf != 1)
  518. goto Badarg;
  519. queuereq(c, r);
  520. teardownclient(c);
  521. }else if(strcmp(f[0], "connect") == 0){
  522. if(c->state != Closed)
  523. goto Badarg;
  524. if(nf != 2)
  525. goto Badarg;
  526. c->connect = estrdup9p(f[1]);
  527. nf = getfields(f[1], f, nelem(f), 0, "!");
  528. if(nf != 2){
  529. free(c->connect);
  530. c->connect = nil;
  531. goto Badarg;
  532. }
  533. c->state = Dialing;
  534. m = allocmsg(conn, SSH_MSG_PORT_OPEN, 4+4+strlen(f[0])+4+4+strlen("localhost"));
  535. putlong(m, c->num);
  536. putstring(m, f[0]);
  537. putlong(m, ndbfindport(f[1]));
  538. putstring(m, "localhost");
  539. queuereq(c, r);
  540. sendmsg(m);
  541. }else{
  542. Badarg:
  543. respond(r, "bad or inappropriate tcp control message");
  544. }
  545. free(s);
  546. }
  547. static void
  548. dataread(Req *r, Client *c)
  549. {
  550. if(c->state != Established){
  551. respond(r, "not connected");
  552. return;
  553. }
  554. queuereq(c, r);
  555. matchmsgs(c);
  556. }
  557. static void
  558. datawrite(Req *r, Client *c)
  559. {
  560. Msg *m;
  561. if(c->state != Established){
  562. respond(r, "not connected");
  563. return;
  564. }
  565. if(r->ifcall.count){
  566. m = allocmsg(conn, SSH_MSG_CHANNEL_DATA, 4+4+r->ifcall.count);
  567. putlong(m, c->servernum);
  568. putlong(m, r->ifcall.count);
  569. putbytes(m, r->ifcall.data, r->ifcall.count);
  570. sendmsg(m);
  571. }
  572. r->ofcall.count = r->ifcall.count;
  573. respond(r, nil);
  574. }
  575. static void
  576. localread(Req *r)
  577. {
  578. char buf[128];
  579. snprint(buf, sizeof buf, "%s!%d\n", remoteip, 0);
  580. readstr(r, buf);
  581. respond(r, nil);
  582. }
  583. static void
  584. remoteread(Req *r, Client *c)
  585. {
  586. char *s;
  587. char buf[128];
  588. s = c->connect;
  589. if(s == nil)
  590. s = "::!0";
  591. snprint(buf, sizeof buf, "%s\n", s);
  592. readstr(r, buf);
  593. respond(r, nil);
  594. }
  595. static void
  596. statusread(Req *r, Client *c)
  597. {
  598. char buf[64];
  599. char *s;
  600. snprint(buf, sizeof buf, "%s!%d", remoteip, 0);
  601. s = statestr[c->state];
  602. readstr(r, s);
  603. respond(r, nil);
  604. }
  605. static void
  606. fsread(Req *r)
  607. {
  608. char e[ERRMAX];
  609. ulong path;
  610. path = r->fid->qid.path;
  611. switch(TYPE(path)){
  612. default:
  613. snprint(e, sizeof e, "bug in fsread path=%lux", path);
  614. respond(r, e);
  615. break;
  616. case Qroot:
  617. dirread9p(r, rootgen, nil);
  618. respond(r, nil);
  619. break;
  620. case Qcs:
  621. csread(r);
  622. break;
  623. case Qtcp:
  624. dirread9p(r, tcpgen, nil);
  625. respond(r, nil);
  626. break;
  627. case Qn:
  628. dirread9p(r, clientgen, client[NUM(path)]);
  629. respond(r, nil);
  630. break;
  631. case Qctl:
  632. ctlread(r, client[NUM(path)]);
  633. break;
  634. case Qdata:
  635. dataread(r, client[NUM(path)]);
  636. break;
  637. case Qlocal:
  638. localread(r);
  639. break;
  640. case Qremote:
  641. remoteread(r, client[NUM(path)]);
  642. break;
  643. case Qstatus:
  644. statusread(r, client[NUM(path)]);
  645. break;
  646. }
  647. }
  648. static void
  649. fswrite(Req *r)
  650. {
  651. ulong path;
  652. char e[ERRMAX];
  653. path = r->fid->qid.path;
  654. switch(TYPE(path)){
  655. default:
  656. snprint(e, sizeof e, "bug in fswrite path=%lux", path);
  657. respond(r, e);
  658. break;
  659. case Qcs:
  660. cswrite(r);
  661. break;
  662. case Qctl:
  663. ctlwrite(r, client[NUM(path)]);
  664. break;
  665. case Qdata:
  666. datawrite(r, client[NUM(path)]);
  667. break;
  668. }
  669. }
  670. static void
  671. fsopen(Req *r)
  672. {
  673. static int need[4] = { 4, 2, 6, 1 };
  674. ulong path;
  675. int n;
  676. Tab *t;
  677. Cs *cs;
  678. /*
  679. * lib9p already handles the blatantly obvious.
  680. * we just have to enforce the permissions we have set.
  681. */
  682. path = r->fid->qid.path;
  683. t = &tab[TYPE(path)];
  684. n = need[r->ifcall.mode&3];
  685. if((n&t->mode) != n){
  686. respond(r, "permission denied");
  687. return;
  688. }
  689. switch(TYPE(path)){
  690. case Qcs:
  691. cs = emalloc(sizeof(Cs));
  692. r->fid->aux = cs;
  693. respond(r, nil);
  694. break;
  695. case Qclone:
  696. n = newclient();
  697. path = PATH(Qctl, n);
  698. r->fid->qid.path = path;
  699. r->ofcall.qid.path = path;
  700. if(chatty9p)
  701. fprint(2, "open clone => path=%lux\n", path);
  702. t = &tab[Qctl];
  703. /* fall through */
  704. default:
  705. if(t-tab >= Qn)
  706. client[NUM(path)]->ref++;
  707. respond(r, nil);
  708. break;
  709. }
  710. }
  711. static void
  712. fsflush(Req *r)
  713. {
  714. int i;
  715. for(i=0; i<nclient; i++)
  716. if(findreq(client[i], r->oldreq))
  717. respond(r->oldreq, "interrupted");
  718. respond(r, nil);
  719. }
  720. static void
  721. handlemsg(Msg *m)
  722. {
  723. int chan, n;
  724. Client *c;
  725. switch(m->type){
  726. case SSH_MSG_DISCONNECT:
  727. case SSH_CMSG_EXIT_CONFIRMATION:
  728. sysfatal("disconnect");
  729. case SSH_CMSG_STDIN_DATA:
  730. case SSH_CMSG_EOF:
  731. case SSH_CMSG_WINDOW_SIZE:
  732. /* don't care */
  733. free(m);
  734. break;
  735. case SSH_MSG_CHANNEL_DATA:
  736. chan = getlong(m);
  737. n = getlong(m);
  738. if(m->rp+n != m->ep)
  739. sysfatal("got bad channel data");
  740. if(chan<nclient && (c=client[chan])->state==Established){
  741. queuemsg(c, m);
  742. matchmsgs(c);
  743. }else
  744. free(m);
  745. break;
  746. case SSH_MSG_CHANNEL_INPUT_EOF:
  747. chan = getlong(m);
  748. free(m);
  749. if(chan<nclient){
  750. c = client[chan];
  751. chan = c->servernum;
  752. hangupclient(c);
  753. m = allocmsg(conn, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  754. putlong(m, chan);
  755. sendmsg(m);
  756. }
  757. break;
  758. case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
  759. chan = getlong(m);
  760. if(chan<nclient)
  761. hangupclient(client[chan]);
  762. free(m);
  763. break;
  764. case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
  765. chan = getlong(m);
  766. c = nil;
  767. if(chan>=nclient || (c=client[chan])->state != Dialing){
  768. if(c)
  769. fprint(2, "cstate %d\n", c->state);
  770. sysfatal("got unexpected open confirmation for %d", chan);
  771. }
  772. c->servernum = getlong(m);
  773. c->state = Established;
  774. dialedclient(c);
  775. free(m);
  776. break;
  777. case SSH_MSG_CHANNEL_OPEN_FAILURE:
  778. chan = getlong(m);
  779. c = nil;
  780. if(chan>=nclient || (c=client[chan])->state != Dialing)
  781. sysfatal("got unexpected open failure");
  782. if(m->rp+4 <= m->ep)
  783. c->servernum = getlong(m);
  784. c->state = Closed;
  785. dialedclient(c);
  786. free(m);
  787. break;
  788. }
  789. }
  790. void
  791. fsnetproc(void*)
  792. {
  793. ulong path;
  794. Alt a[4];
  795. Cs *cs;
  796. Fid *fid;
  797. Req *r;
  798. Msg *m;
  799. threadsetname("fsthread");
  800. a[0].op = CHANRCV;
  801. a[0].c = fsclunkchan;
  802. a[0].v = &fid;
  803. a[1].op = CHANRCV;
  804. a[1].c = fsreqchan;
  805. a[1].v = &r;
  806. a[2].op = CHANRCV;
  807. a[2].c = sshmsgchan;
  808. a[2].v = &m;
  809. a[3].op = CHANEND;
  810. for(;;){
  811. switch(alt(a)){
  812. case 0:
  813. path = fid->qid.path;
  814. switch(TYPE(path)){
  815. case Qcs:
  816. cs = fid->aux;
  817. if(cs){
  818. free(cs->resp);
  819. free(cs);
  820. }
  821. break;
  822. }
  823. if(fid->omode != -1 && TYPE(path) >= Qn)
  824. closeclient(client[NUM(path)]);
  825. sendp(fsclunkwaitchan, nil);
  826. break;
  827. case 1:
  828. switch(r->ifcall.type){
  829. case Tattach:
  830. fsattach(r);
  831. break;
  832. case Topen:
  833. fsopen(r);
  834. break;
  835. case Tread:
  836. fsread(r);
  837. break;
  838. case Twrite:
  839. fswrite(r);
  840. break;
  841. case Tstat:
  842. fsstat(r);
  843. break;
  844. case Tflush:
  845. fsflush(r);
  846. break;
  847. default:
  848. respond(r, "bug in fsthread");
  849. break;
  850. }
  851. sendp(fsreqwaitchan, 0);
  852. break;
  853. case 2:
  854. handlemsg(m);
  855. break;
  856. }
  857. }
  858. }
  859. static void
  860. fssend(Req *r)
  861. {
  862. sendp(fsreqchan, r);
  863. recvp(fsreqwaitchan); /* avoids need to deal with spurious flushes */
  864. }
  865. static void
  866. fsdestroyfid(Fid *fid)
  867. {
  868. sendp(fsclunkchan, fid);
  869. recvp(fsclunkwaitchan);
  870. }
  871. void
  872. takedown(Srv*)
  873. {
  874. threadexitsall("done");
  875. }
  876. Srv fs =
  877. {
  878. .attach= fssend,
  879. .destroyfid= fsdestroyfid,
  880. .walk1= fswalk1,
  881. .open= fssend,
  882. .read= fssend,
  883. .write= fssend,
  884. .stat= fssend,
  885. .flush= fssend,
  886. .end= takedown,
  887. };
  888. void
  889. threadmain(int argc, char **argv)
  890. {
  891. int i, fd;
  892. char *host, *user, *p, *service;
  893. char *f[16];
  894. Msg *m;
  895. static Conn c;
  896. fmtinstall('B', mpfmt);
  897. fmtinstall('H', encodefmt);
  898. mtpt = "/net";
  899. service = nil;
  900. user = nil;
  901. ARGBEGIN{
  902. case 'B': /* undocumented, debugging */
  903. doabort = 1;
  904. break;
  905. case 'D': /* undocumented, debugging */
  906. debuglevel = strtol(EARGF(usage()), nil, 0);
  907. break;
  908. case '9': /* undocumented, debugging */
  909. chatty9p++;
  910. break;
  911. case 'A':
  912. authlist = EARGF(usage());
  913. break;
  914. case 'c':
  915. cipherlist = EARGF(usage());
  916. break;
  917. case 'm':
  918. mtpt = EARGF(usage());
  919. break;
  920. case 's':
  921. service = EARGF(usage());
  922. break;
  923. default:
  924. usage();
  925. }ARGEND
  926. if(argc != 1)
  927. usage();
  928. host = argv[0];
  929. if((p = strchr(host, '@')) != nil){
  930. *p++ = '\0';
  931. user = host;
  932. host = p;
  933. }
  934. if(user == nil)
  935. user = getenv("user");
  936. if(user == nil)
  937. sysfatal("cannot find user name");
  938. privatefactotum();
  939. if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
  940. sysfatal("dialing %s: %r", host);
  941. c.interactive = isatty(0);
  942. c.fd[0] = c.fd[1] = fd;
  943. c.user = user;
  944. c.host = host;
  945. setaliases(&c, host);
  946. c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
  947. c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
  948. for(i=0; i<c.nokcipher; i++)
  949. c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
  950. c.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
  951. c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
  952. for(i=0; i<c.nokauth; i++)
  953. c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
  954. sshclienthandshake(&c);
  955. requestpty(&c); /* turns on TCP_NODELAY on other side */
  956. m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
  957. sendmsg(m);
  958. time0 = time(0);
  959. sshmsgchan = chancreate(sizeof(Msg*), 16);
  960. fsreqchan = chancreate(sizeof(Req*), 0);
  961. fsreqwaitchan = chancreate(sizeof(void*), 0);
  962. fsclunkchan = chancreate(sizeof(Fid*), 0);
  963. fsclunkwaitchan = chancreate(sizeof(void*), 0);
  964. conn = &c;
  965. procrfork(sshreadproc, &c, 8192, RFNAMEG|RFNOTEG);
  966. procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG);
  967. threadpostmountsrv(&fs, service, mtpt, MREPL);
  968. exits(0);
  969. }