sshnet.c 18 KB

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