1 /*
2 * /net/ssh
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <fcall.h>
7 #include <thread.h>
8 #include <9p.h>
9 #include <mp.h>
10 #include <auth.h>
11 #include <authsrv.h>
12 #include <libsec.h>
13 #include <ip.h>
14 #include "netssh.h"
15
16 extern int nokeyverify;
17
18 void stclunk(Fid *);
19 void stend(Srv *);
20 void stflush(Req *);
21 void stopen(Req *);
22 void stread(Req *);
23 void stwrite(Req *);
24
25 Srv netsshsrv = {
26 .open = stopen,
27 .read = stread,
28 .write = stwrite,
29 .flush = stflush,
30 .destroyfid = stclunk,
31 .end = stend,
32 };
33
34 Cipher *cryptos[] = {
35 &cipheraes128,
36 &cipheraes192,
37 &cipheraes256,
38 // &cipherblowfish,
39 &cipher3des,
40 &cipherrc4,
41 };
42
43 Kex *kexes[] = {
44 &dh1sha1,
45 &dh14sha1,
46 };
47
48 PKA *pkas[3];
49
50 char *macnames[] = {
51 "hmac-sha1",
52 };
53
54 char *st_names[] = {
55 [Empty] "Empty",
56 [Allocated] "Allocated",
57 [Initting] "Initting",
58 [Listening] "Listening",
59 [Opening] "Opening",
60 [Negotiating] "Negotiating",
61 [Authing] "Authing",
62 [Established] "Established",
63 [Eof] "Eof",
64 [Closing] "Closing",
65 [Closed] "Closed",
66 };
67
68 int debug;
69 int kflag;
70 char *mntpt = "/net";
71 char uid[32];
72 Conn *connections[MAXCONN];
73 File *rootfile, *clonefile, *ctlfile, *keysfile;
74 Ioproc *io9p;
75 MBox keymbox;
76 QLock availlck;
77 Rendez availrend;
78
79 SSHChan *alloc_chan(Conn *);
80 Conn *alloc_conn(void);
81 int auth_req(Packet *, Conn *);
82 int client_auth(Conn *, Ioproc *);
83 int dohandshake(Conn *, char *);
84 char *factlookup(int, int, char *[]);
85 void filedup(Req *, File *);
86 void readdata(void *);
87 void reader(void *);
88 void readreqrem(void *);
89 void send_kexinit(Conn *);
90 void server(char *, char *);
91 void shutdown(Conn *);
92 void stlisconn(void *);
93 void stlischan(void *);
94 int validatekex(Conn *, Packet *);
95 int validatekexc(Packet *);
96 int validatekexs(Packet *);
97 void writectlproc(void *);
98 void writedataproc(void *);
99 void writereqremproc(void *);
100
101 static int deferredinit(Conn *c);
102
103 static void
sshlogint(Conn * c,char * file,char * p)104 sshlogint(Conn *c, char *file, char *p)
105 {
106 char *role, *id;
107
108 if (c == nil)
109 role = "";
110 else if (c->role == Server)
111 role = "server ";
112 else
113 role = "client ";
114 if (c == nil)
115 id = strdup("");
116 else if (c->user || c->remote)
117 id = smprint("user %s@%s id %d ", c->user, c->remote, c->id);
118 else
119 id = smprint("id %d ", c->id);
120
121 syslog(0, file, "%s: %s%s%s", argv0, role, id, p);
122 free(id);
123 }
124
125 void
sshlog(Conn * c,char * fmt,...)126 sshlog(Conn *c, char *fmt, ...)
127 {
128 va_list args;
129 char *p;
130
131 /* do this first in case fmt contains "%r" */
132 va_start(args, fmt);
133 p = vsmprint(fmt, args);
134 va_end(args);
135
136 sshlogint(c, "ssh", p);
137 sshlogint(c, "sshdebug", p); /* log in both places */
138 free(p);
139 }
140
141 void
sshdebug(Conn * c,char * fmt,...)142 sshdebug(Conn *c, char *fmt, ...)
143 {
144 va_list args;
145 char *p;
146
147 if (!debug)
148 return;
149
150 /* do this first in case fmt contains "%r" */
151 va_start(args, fmt);
152 p = vsmprint(fmt, args);
153 va_end(args);
154
155 sshlogint(c, "sshdebug", p);
156 free(p);
157 }
158
159 void
usage(void)160 usage(void)
161 {
162 fprint(2, "usage: %s [-dkv] [-m mntpt] [-s srvpt]\n", argv0);
163 exits("usage");
164 }
165
166 void
threadmain(int argc,char * argv[])167 threadmain(int argc, char *argv[])
168 {
169 char *p, *srvpt = nil;
170
171 quotefmtinstall();
172 threadsetname("main");
173 nokeyverify = 1; /* temporary until verification is fixed */
174 ARGBEGIN {
175 case '9':
176 chatty9p = 1;
177 break;
178 case 'd':
179 debug++;
180 break;
181 case 'k':
182 kflag = 1;
183 break;
184 case 'm':
185 mntpt = EARGF(usage());
186 break;
187 case 's':
188 srvpt = EARGF(usage());
189 break;
190 case 'v':
191 nokeyverify = 1;
192 break;
193 case 'V':
194 nokeyverify = 0;
195 break;
196 default:
197 usage();
198 break;
199 } ARGEND;
200
201 p = getenv("nosshkeyverify");
202 if (p && p[0] != '\0')
203 nokeyverify = 1;
204 free(p);
205
206 if (readfile("/dev/user", uid, sizeof uid) <= 0)
207 strcpy(uid, "none");
208
209 keymbox.mchan = chancreate(4, 0);
210 availrend.l = &availlck;
211 dh_init(pkas);
212
213 /* become a daemon */
214 if (rfork(RFNOTEG) < 0)
215 fprint(2, "%s: rfork(NOTEG) failed: %r\n", argv0);
216 server(mntpt, srvpt);
217 threadexits(nil);
218 }
219
220 int
readio(Ioproc * io,int fd,void * buf,int n)221 readio(Ioproc *io, int fd, void *buf, int n)
222 {
223 if (io)
224 return ioread(io, fd, buf, n);
225 else
226 return read(fd, buf, n);
227 }
228
229 int
writeio(Ioproc * io,int fd,void * buf,int n)230 writeio(Ioproc *io, int fd, void *buf, int n)
231 {
232 if (io)
233 return iowrite(io, fd, buf, n);
234 else
235 return write(fd, buf, n);
236 }
237
238 int
read9pmsg(int fd,void * abuf,uint n)239 read9pmsg(int fd, void *abuf, uint n)
240 {
241 int m, len;
242 uchar *buf;
243
244 if (io9p == nil)
245 io9p = ioproc();
246
247 buf = abuf;
248
249 /* read count */
250 m = ioreadn(io9p, fd, buf, BIT32SZ);
251 if(m != BIT32SZ){
252 if(m < 0)
253 return -1;
254 return 0;
255 }
256
257 len = GBIT32(buf);
258 if(len <= BIT32SZ || len > n){
259 werrstr("bad length in 9P2000 message header");
260 return -1;
261 }
262 len -= BIT32SZ;
263 m = ioreadn(io9p, fd, buf+BIT32SZ, len);
264 if(m < len)
265 return 0;
266 return BIT32SZ+m;
267 }
268
269 void
stend(Srv *)270 stend(Srv *)
271 {
272 closeioproc(io9p);
273 threadkillgrp(threadgetgrp());
274 }
275
276 void
server(char * mntpt,char * srvpt)277 server(char *mntpt, char *srvpt)
278 {
279 Dir d;
280 char *p;
281 int fd;
282
283 netsshsrv.tree = alloctree(uid, uid, 0777, nil);
284 rootfile = createfile(netsshsrv.tree->root, "ssh", uid, 0555|DMDIR,
285 (void*)Qroot);
286 clonefile = createfile(rootfile, "clone", uid, 0666, (void*)Qclone);
287 ctlfile = createfile(rootfile, "ctl", uid, 0666, (void*)Qctl);
288 keysfile = createfile(rootfile, "keys", uid, 0600, (void *)Qreqrem);
289
290 /*
291 * needs to be MBEFORE in case there are previous, now defunct,
292 * netssh processes mounted in mntpt.
293 */
294 threadpostmountsrv(&netsshsrv, srvpt, mntpt, MBEFORE);
295
296 p = esmprint("%s/cs", mntpt);
297 fd = open(p, OWRITE);
298 free(p);
299 if (fd >= 0) {
300 fprint(fd, "add ssh");
301 close(fd);
302 }
303 if (srvpt) {
304 nulldir(&d);
305 d.mode = 0666;
306 p = esmprint("/srv/%s", srvpt);
307 dirwstat(p, &d);
308 free(p);
309 }
310 sshdebug(nil, "server started for %s", getuser());
311 }
312
313 static void
respexit(Conn * c,Req * r,void * freeme,char * msg)314 respexit(Conn *c, Req *r, void *freeme, char *msg)
315 {
316 if (msg)
317 sshdebug(c, "%s", msg);
318 r->aux = 0;
319 respond(r, msg);
320 free(freeme);
321 threadexits(nil); /* maybe use msg here */
322 }
323
324 void
stopen(Req * r)325 stopen(Req *r)
326 {
327 int lev, xconn, fd;
328 uvlong qidpath;
329 char *p;
330 char buf[32];
331 Conn *c;
332 SSHChan *sc;
333
334 qidpath = (uvlong)r->fid->file->aux;
335 lev = qidpath >> Levshift;
336 switch ((ulong)(qidpath & Qtypemask)) {
337 default:
338 respond(r, nil);
339 break;
340 case Qlisten:
341 r->aux = (void *)threadcreate((lev == Connection?
342 stlisconn: stlischan), r, Defstk);
343 break;
344 case Qclone:
345 switch (lev) {
346 case Top:
347 /* should use dial(2) instead of diddling /net/tcp */
348 p = esmprint("%s/tcp/clone", mntpt);
349 fd = open(p, ORDWR);
350 if (fd < 0) {
351 sshdebug(nil, "stopen: open %s failed: %r", p);
352 free(p);
353 responderror(r);
354 return;
355 }
356 free(p);
357
358 c = alloc_conn();
359 if (c == nil) {
360 close(fd);
361 respond(r, "no more connections");
362 return;
363 }
364 c->ctlfd = fd;
365 c->poisoned = 0;
366 filedup(r, c->ctlfile);
367 sshlog(c, "new connection on fd %d", fd);
368 break;
369 case Connection:
370 xconn = (qidpath >> Connshift) & Connmask;
371 c = connections[xconn];
372 if (c == nil) {
373 respond(r, "bad connection");
374 return;
375 }
376 sc = alloc_chan(c);
377 if (sc == nil) {
378 respond(r, "no more channels");
379 return;
380 }
381 filedup(r, sc->ctl);
382 break;
383 default:
384 snprint(buf, sizeof buf, "bad level %d", lev);
385 readstr(r, buf);
386 break;
387 }
388 respond(r, nil);
389 break;
390 }
391 }
392
393 static void
listerrexit(Req * r,Ioproc * io,Conn * cl)394 listerrexit(Req *r, Ioproc *io, Conn *cl)
395 {
396 r->aux = 0;
397 responderror(r);
398 closeioproc(io);
399 shutdown(cl);
400 threadexits(nil);
401 }
402
403 void
stlisconn(void * a)404 stlisconn(void *a)
405 {
406 int xconn, fd, n;
407 uvlong qidpath;
408 char *msg;
409 char buf[Numbsz], path[NETPATHLEN];
410 Conn *c, *cl;
411 Ioproc *io;
412 Req *r;
413
414 threadsetname("stlisconn");
415 r = a;
416 qidpath = (uvlong)r->fid->file->aux;
417 xconn = (qidpath >> Connshift) & Connmask;
418
419 cl = connections[xconn];
420 if (cl == nil) {
421 sshlog(cl, "bad connection");
422 respond(r, "bad connection");
423 threadexits("bad connection");
424 }
425 if (cl->poisoned) {
426 sshdebug(cl, "stlisconn conn %d poisoned", xconn);
427 r->aux = 0;
428 respond(r, "top level listen conn poisoned");
429 threadexits("top level listen conn poisoned");
430 }
431 if (cl->ctlfd < 0) {
432 sshdebug(cl, "stlisconn conn %d ctlfd < 0; poisoned", xconn);
433 r->aux = 0;
434 respond(r, "top level listen with closed fd");
435 shutdown(cl);
436 cl->poisoned = 1; /* no more use until ctlfd is set */
437 threadexits("top level listen with closed fd");
438 }
439
440 io = ioproc();
441
442 /* read xconn's tcp conn's ctl file */
443 seek(cl->ctlfd, 0, 0);
444 n = ioread(io, cl->ctlfd, buf, sizeof buf - 1);
445 if (n == 0) {
446 sshlog(cl, "stlisconn read eof on fd %d", cl->ctlfd);
447 listerrexit(r, io, cl);
448 } else if (n < 0) {
449 sshlog(cl, "stlisconn read failed on fd %d: %r", cl->ctlfd);
450 listerrexit(r, io, cl);
451 }
452 buf[n] = '\0';
453
454 cl->state = Listening;
455 /* should use dial(2) instead of diddling /net/tcp */
456 snprint(path, sizeof path, "%s/tcp/%s/listen", mntpt, buf);
457 for(;;) {
458 fd = ioopen(io, path, ORDWR);
459 if (fd < 0)
460 listerrexit(r, io, cl);
461 c = alloc_conn();
462 if (c)
463 break;
464 n = ioread(io, fd, buf, sizeof buf - 1);
465 if (n <= 0)
466 listerrexit(r, io, cl);
467 buf[n] = '\0';
468 msg = smprint("reject %s no available connections", buf);
469 iowrite(io, fd, msg, strlen(msg));
470 free(msg);
471 close(fd); /* surely ioclose? */
472 }
473 c->ctlfd = fd;
474 if (c->ctlfd < 0) {
475 sshlog(cl, "stlisconn c->ctlfd < 0 for conn %d", xconn);
476 threadexitsall("stlisconn c->ctlfd < 0");
477 }
478 c->poisoned = 0;
479 c->stifle = 1; /* defer server; was for coexistence */
480 filedup(r, c->ctlfile);
481 sshdebug(c, "responding to listen open");
482 r->aux = 0;
483 respond(r, nil);
484 closeioproc(io);
485 threadexits(nil);
486 }
487
488 void
stlischan(void * a)489 stlischan(void *a)
490 {
491 Req *r;
492 Packet *p2;
493 Ioproc *io;
494 Conn *c;
495 SSHChan *sc;
496 int i, n, xconn;
497 uvlong qidpath;
498
499 threadsetname("stlischan");
500 r = a;
501 qidpath = (uvlong)r->fid->file->aux;
502 xconn = (qidpath >> Connshift) & Connmask;
503 c = connections[xconn];
504 if (c == nil) {
505 respond(r, "bad channel");
506 sshlog(c, "bad channel");
507 threadexits(nil);
508 }
509 if (c->state == Closed || c->state == Closing)
510 respexit(c, r, nil, "channel listen on closed connection");
511 sc = c->chans[qidpath & Chanmask];
512
513 qlock(&c->l);
514 sc->lreq = r;
515 for (i = 0; i < c->nchan; ++i)
516 if (c->chans[i] && c->chans[i]->state == Opening &&
517 c->chans[i]->ann && strcmp(c->chans[i]->ann, sc->ann) == 0)
518 break;
519 if (i >= c->nchan) {
520 sc->state = Listening;
521 rsleep(&sc->r);
522 i = sc->waker;
523 if (i < 0) {
524 qunlock(&c->l);
525 r->aux = 0;
526 responderror(r);
527 threadexits(nil);
528 }
529 } else
530 rwakeup(&c->chans[i]->r);
531 qunlock(&c->l);
532
533 if (c->state == Closed || c->state == Closing || c->state == Eof)
534 respexit(c, r, nil, "channel listen on closed connection");
535 c->chans[i]->state = Established;
536
537 p2 = new_packet(c);
538 c->chans[i]->rwindow = Maxpayload;
539 add_byte(p2, SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
540 hnputl(p2->payload + 1, c->chans[i]->otherid);
541 hnputl(p2->payload + 5, c->chans[i]->id);
542 hnputl(p2->payload + 9, Maxpayload);
543 hnputl(p2->payload + 13, Maxrpcbuf);
544 p2->rlength = 18;
545 n = finish_packet(p2);
546 filedup(r, c->chans[i]->ctl);
547
548 io = ioproc();
549 n = iowrite(io, c->datafd, p2->nlength, n);
550 closeioproc(io);
551
552 free(p2);
553
554 sshdebug(c, "responding to chan listen open");
555 r->aux = 0;
556 if (n < 0)
557 responderror(r);
558 else
559 respond(r, nil);
560 threadexits(nil);
561 }
562
563 void
getdata(Conn * c,SSHChan * sc,Req * r)564 getdata(Conn *c, SSHChan *sc, Req *r)
565 {
566 Packet *p;
567 Plist *d;
568 int n;
569
570 n = r->ifcall.count;
571 if (sc->dataq->rem < n)
572 n = sc->dataq->rem;
573 if (n > Maxrpcbuf)
574 n = Maxrpcbuf;
575 r->ifcall.offset = 0;
576
577 readbuf(r, sc->dataq->st, n);
578 sc->dataq->st += n;
579 sc->dataq->rem -= n;
580 sc->inrqueue -= n;
581 if (sc->dataq->rem <= 0) {
582 d = sc->dataq;
583 sc->dataq = sc->dataq->next;
584 if (d->pack->tlength > sc->rwindow)
585 sc->rwindow = 0;
586 else
587 sc->rwindow -= d->pack->tlength;
588 free(d->pack);
589 free(d);
590 }
591 if (sc->rwindow < 16*1024) { /* magic. half-way, maybe? */
592 sc->rwindow += Maxpayload;
593 sshdebug(c, "increasing receive window to %lud, inq %lud\n",
594 argv0, sc->rwindow, sc->inrqueue);
595 p = new_packet(c);
596 add_byte(p, SSH_MSG_CHANNEL_WINDOW_ADJUST);
597 hnputl(p->payload+1, sc->otherid);
598 hnputl(p->payload+5, Maxpayload);
599 p->rlength += 8;
600 n = finish_packet(p);
601 iowrite(c->dio, c->datafd, p->nlength, n);
602 free(p);
603 }
604 r->aux = 0;
605 respond(r, nil);
606 }
607
608 void
stread(Req * r)609 stread(Req *r)
610 {
611 Conn *c;
612 SSHChan *sc;
613 int n, lev, cnum, xconn;
614 uvlong qidpath;
615 char buf[Arbbufsz], path[NETPATHLEN];
616
617 threadsetname("stread");
618 qidpath = (uvlong)r->fid->file->aux;
619 lev = qidpath >> Levshift;
620 xconn = (qidpath >> Connshift) & Connmask;
621 c = connections[xconn];
622 if (c == nil) {
623 if (lev != Top || (qidpath & Qtypemask) != Qreqrem) {
624 respond(r, "Invalid connection");
625 return;
626 }
627 cnum = 0;
628 sc = nil;
629 } else {
630 cnum = qidpath & Chanmask;
631 sc = c->chans[cnum];
632 }
633 switch ((ulong)(qidpath & Qtypemask)) {
634 case Qctl:
635 case Qlisten:
636 if (r->ifcall.offset != 0) {
637 respond(r, nil);
638 break;
639 }
640 switch (lev) {
641 case Top:
642 readstr(r, st_names[c->state]);
643 break;
644 case Connection:
645 case Subchannel:
646 snprint(buf, sizeof buf, "%d", lev == Connection?
647 xconn: cnum);
648 readstr(r, buf);
649 break;
650 default:
651 snprint(buf, sizeof buf, "stread error, level %d", lev);
652 respond(r, buf);
653 return;
654 }
655 respond(r, nil);
656 break;
657 case Qclone:
658 if (r->ifcall.offset != 0) {
659 respond(r, nil);
660 break;
661 }
662 readstr(r, "Congratulations, you've achieved the impossible\n");
663 respond(r, nil);
664 break;
665 case Qdata:
666 if (lev == Top) {
667 respond(r, nil);
668 break;
669 }
670 if (lev == Connection) {
671 if (0 && c->stifle) { /* was for coexistence */
672 c->stifle = 0;
673 if (deferredinit(c) < 0) {
674 respond(r, "deferredinit failed");
675 break;
676 }
677 }
678 if (c->cap) /* auth capability? */
679 readstr(r, c->cap);
680 respond(r, nil);
681 break;
682 }
683
684 r->aux = (void *)threadcreate(readdata, r, Defstk);
685 break;
686 case Qlocal:
687 if (lev == Connection)
688 if (c->ctlfd < 0)
689 readstr(r, "::!0\n");
690 else {
691 n = pread(c->ctlfd, buf, 10, 0); // magic 10
692 buf[n >= 0? n: 0] = '\0';
693 snprint(path, sizeof path, "%s/tcp/%s/local",
694 mntpt, buf);
695 readfile(path, buf, sizeof buf);
696 readstr(r, buf);
697 }
698 respond(r, nil);
699 break;
700 case Qreqrem:
701 r->aux = (void *)threadcreate(readreqrem, r, Defstk);
702 break;
703 case Qstatus:
704 switch (lev) {
705 case Top:
706 readstr(r, "Impossible");
707 break;
708 case Connection:
709 readstr(r, (uint)c->state > Closed?
710 "Unknown": st_names[c->state]);
711 break;
712 case Subchannel:
713 readstr(r, (uint)sc->state > Closed?
714 "Unknown": st_names[sc->state]);
715 break;
716 }
717 respond(r, nil);
718 break;
719 case Qtcp:
720 /* connection number of underlying tcp connection */
721 if (lev == Connection)
722 if (c->ctlfd < 0)
723 readstr(r, "-1\n");
724 else {
725 n = pread(c->ctlfd, buf, 10, 0); /* magic 10 */
726 buf[n >= 0? n: 0] = '\0';
727 readstr(r, buf);
728 }
729 respond(r, nil);
730 break;
731 default:
732 respond(r, nil);
733 break;
734 }
735 }
736
737 void
readreqrem(void * a)738 readreqrem(void *a)
739 {
740 Ioproc *io;
741 Req *r;
742 Conn *c;
743 SSHChan *sc;
744 int fd, n, lev, cnum, xconn;
745 uvlong qidpath;
746 char buf[Arbbufsz], path[NETPATHLEN];
747
748 threadsetname("readreqrem");
749 r = a;
750 qidpath = (uvlong)r->fid->file->aux;
751 lev = qidpath >> Levshift;
752 xconn = (qidpath >> Connshift) & Connmask;
753 c = connections[xconn];
754 if (c == nil) {
755 if (lev != Top) {
756 respond(r, "Invalid connection");
757 return;
758 }
759 sc = nil;
760 } else {
761 cnum = qidpath & Chanmask;
762 sc = c->chans[cnum];
763 }
764 switch (lev) {
765 case Top:
766 if (r->ifcall.offset == 0 && keymbox.state != Empty) {
767 r->aux = 0;
768 respond(r, "Key file collision"); /* WTF? */
769 break;
770 }
771 if (r->ifcall.offset != 0) {
772 readstr(r, keymbox.msg);
773 r->aux = 0;
774 respond(r, nil);
775 if (r->ifcall.offset + r->ifcall.count >=
776 strlen(keymbox.msg))
777 keymbox.state = Empty;
778 else
779 keymbox.state = Allocated;
780 break;
781 }
782 keymbox.state = Allocated;
783 for(;;) {
784 if (keymbox.msg == nil)
785 if (recv(keymbox.mchan, nil) < 0) {
786 r->aux = 0;
787 responderror(r);
788 keymbox.state = Empty;
789 threadexits(nil);
790 }
791 if (keymbox.state == Empty)
792 break;
793 else if (keymbox.state == Allocated) {
794 if (keymbox.msg) {
795 readstr(r, keymbox.msg);
796 if (r->ifcall.offset + r->ifcall.count
797 >= strlen(keymbox.msg)) {
798 free(keymbox.msg);
799 keymbox.msg = nil;
800 keymbox.state = Empty;
801 }
802 }
803 break;
804 }
805 }
806 r->aux = 0;
807 respond(r, nil);
808 break;
809 case Connection:
810 if (c->ctlfd >= 0) {
811 io = ioproc();
812 seek(c->ctlfd, 0, 0);
813 n = ioread(io, c->ctlfd, buf, 10); /* magic 10 */
814 if (n < 0) {
815 r->aux = 0;
816 responderror(r);
817 closeioproc(io);
818 break;
819 }
820 buf[n] = '\0';
821 snprint(path, NETPATHLEN, "%s/tcp/%s/remote", mntpt, buf);
822 if ((fd = ioopen(io, path, OREAD)) < 0 ||
823 (n = ioread(io, fd, buf, Arbbufsz - 1)) < 0) {
824 r->aux = 0;
825 responderror(r);
826 if (fd >= 0)
827 ioclose(io, fd);
828 closeioproc(io);
829 break;
830 }
831 ioclose(io, fd);
832 closeioproc(io);
833 buf[n] = '\0';
834 readstr(r, buf);
835 } else
836 readstr(r, "::!0\n");
837 r->aux = 0;
838 respond(r, nil);
839 break;
840 case Subchannel:
841 if ((sc->state == Closed || sc->state == Closing ||
842 sc->state == Eof) && sc->reqq == nil && sc->dataq == nil) {
843 sshdebug(c, "sending EOF1 to channel request listener");
844 r->aux = 0;
845 respond(r, nil);
846 break;
847 }
848 while (sc->reqq == nil) {
849 if (recv(sc->reqchan, nil) < 0) {
850 r->aux = 0;
851 responderror(r);
852 threadexits(nil);
853 }
854 if ((sc->state == Closed || sc->state == Closing ||
855 sc->state == Eof) && sc->reqq == nil &&
856 sc->dataq == nil) {
857 sshdebug(c, "sending EOF2 to channel request "
858 "listener");
859 respexit(c, r, nil, nil);
860 }
861 }
862 n = r->ifcall.count;
863 if (sc->reqq->rem < n)
864 n = sc->reqq->rem;
865 if (n > Maxrpcbuf)
866 n = Maxrpcbuf;
867 r->ifcall.offset = 0;
868 readbuf(r, sc->reqq->st, n);
869 sc->reqq->st += n;
870 sc->reqq->rem -= n;
871 if (sc->reqq->rem <= 0) {
872 Plist *d = sc->reqq;
873 sc->reqq = sc->reqq->next;
874 free(d->pack);
875 free(d);
876 }
877 r->aux = 0;
878 respond(r, nil);
879 break;
880 }
881 threadexits(nil);
882 }
883
884 void
readdata(void * a)885 readdata(void *a)
886 {
887 Req *r;
888 Conn *c;
889 SSHChan *sc;
890 int cnum, xconn;
891 uvlong qidpath;
892
893 threadsetname("readdata");
894 r = a;
895 qidpath = (uvlong)r->fid->file->aux;
896 xconn = (qidpath >> Connshift) & Connmask;
897 c = connections[xconn];
898 if (c == nil) {
899 respond(r, "bad connection");
900 sshlog(c, "bad connection");
901 threadexits(nil);
902 }
903 cnum = qidpath & Chanmask;
904 sc = c->chans[cnum];
905 if (sc->dataq == nil && (sc->state == Closed || sc->state == Closing ||
906 sc->state == Eof)) {
907 sshdebug(c, "sending EOF1 to channel listener");
908 r->aux = 0;
909 respond(r, nil);
910 threadexits(nil);
911 }
912 if (sc->dataq != nil) {
913 getdata(c, sc, r);
914 threadexits(nil);
915 }
916 while (sc->dataq == nil) {
917 if (recv(sc->inchan, nil) < 0) {
918 sshdebug(c, "got interrupt/error in readdata %r");
919 r->aux = 0;
920 responderror(r);
921 threadexits(nil);
922 }
923 if (sc->dataq == nil && (sc->state == Closed ||
924 sc->state == Closing || sc->state == Eof)) {
925 sshdebug(c, "sending EOF2 to channel listener");
926 r->aux = 0;
927 respond(r, nil);
928 threadexits(nil);
929 }
930 }
931 getdata(c, sc, r);
932 threadexits(nil);
933 }
934
935 void
stwrite(Req * r)936 stwrite(Req *r)
937 {
938 Conn *c;
939 SSHChan *ch;
940 int lev, xconn;
941 uvlong qidpath;
942
943 threadsetname("stwrite");
944 qidpath = (uvlong)r->fid->file->aux;
945 lev = qidpath >> Levshift;
946 xconn = (qidpath >> Connshift) & Connmask;
947 c = connections[xconn];
948 if (c == nil) {
949 respond(r, "invalid connection");
950 return;
951 }
952 ch = c->chans[qidpath & Chanmask];
953 switch ((ulong)(qidpath & Qtypemask)) {
954 case Qclone:
955 case Qctl:
956 r->aux = (void *)threadcreate(writectlproc, r, Defstk);
957 break;
958 case Qdata:
959 r->ofcall.count = r->ifcall.count;
960 if (lev == Top || lev == Connection ||
961 c->state == Closed || c->state == Closing ||
962 ch->state == Closed || ch->state == Closing) {
963 respond(r, nil);
964 break;
965 }
966 if (0 && c->stifle) { /* was for coexistence */
967 c->stifle = 0;
968 if (deferredinit(c) < 0) {
969 respond(r, "deferredinit failed");
970 break;
971 }
972 }
973 r->aux = (void *)threadcreate(writedataproc, r, Defstk);
974 break;
975 case Qreqrem:
976 r->aux = (void *)threadcreate(writereqremproc, r, Defstk);
977 break;
978 default:
979 respond(r, nil);
980 break;
981 }
982 }
983
984 static int
dialbyhand(Conn * c,int ntok,char * toks[])985 dialbyhand(Conn *c, int ntok, char *toks[])
986 {
987 /*
988 * this uses /net/tcp to connect directly.
989 * should use dial(2) instead of doing it by hand.
990 */
991 sshdebug(c, "tcp connect %s %s", toks[1], ntok > 3? toks[2]: "");
992 return fprint(c->ctlfd, "connect %s %s", toks[1], ntok > 3? toks[2]: "");
993 }
994
995 static void
userauth(Conn * c,Req * r,char * buf,int ntok,char * toks[])996 userauth(Conn *c, Req *r, char *buf, int ntok, char *toks[])
997 {
998 int n;
999 char *attrs[5];
1000 Packet *p;
1001
1002 if (ntok < 3 || ntok > 4)
1003 respexit(c, r, buf, "bad connect command");
1004 if (!c->service)
1005 c->service = estrdup9p(toks[0]);
1006 if (c->user)
1007 free(c->user);
1008 c->user = estrdup9p(toks[2]);
1009 sshdebug(c, "userauth for user %s", c->user);
1010
1011 if (ntok == 4 && strcmp(toks[1], "k") == 0) {
1012 if (c->authkey) {
1013 free(c->authkey);
1014 c->authkey = nil;
1015 }
1016 if (c->password)
1017 free(c->password);
1018 c->password = estrdup9p(toks[3]);
1019 sshdebug(c, "userauth got password");
1020 } else {
1021 if (c->password) {
1022 free(c->password);
1023 c->password = nil;
1024 }
1025 memset(attrs, 0, sizeof attrs);
1026 attrs[0] = "proto=rsa";
1027 attrs[1] = "!dk?";
1028 attrs[2] = smprint("user=%s", c->user);
1029 attrs[3] = smprint("sys=%s", c->remote);
1030 if (c->authkey)
1031 free(c->authkey);
1032 sshdebug(c, "userauth trying rsa");
1033 if (ntok == 3)
1034 c->authkey = factlookup(4, 2, attrs);
1035 else {
1036 attrs[4] = toks[3];
1037 c->authkey = factlookup(5, 2, attrs);
1038 }
1039 free(attrs[2]);
1040 free(attrs[3]);
1041 }
1042
1043 if (!c->password && !c->authkey)
1044 respexit(c, r, buf, "no auth info");
1045 else if (c->state != Authing) {
1046 p = new_packet(c);
1047 add_byte(p, SSH_MSG_SERVICE_REQUEST);
1048 add_string(p, c->service);
1049 n = finish_packet(p);
1050 sshdebug(c, "sending msg svc req for %s", c->service);
1051 if (writeio(c->dio, c->datafd, p->nlength, n) != n) {
1052 sshdebug(c, "authing write failed: %r");
1053 free(p);
1054 r->aux = 0;
1055 responderror(r);
1056 free(buf);
1057 threadexits(nil);
1058 }
1059 free(p);
1060 } else
1061 if (client_auth(c, c->dio) < 0)
1062 respexit(c, r, buf, "ssh-userauth client auth failed");
1063 qlock(&c->l);
1064 if (c->state != Established) {
1065 sshdebug(c, "sleeping for auth");
1066 rsleep(&c->r);
1067 }
1068 qunlock(&c->l);
1069 if (c->state != Established)
1070 respexit(c, r, buf, "ssh-userath auth failed (not Established)");
1071 }
1072
1073 void
writectlproc(void * a)1074 writectlproc(void *a)
1075 {
1076 Req *r;
1077 Packet *p;
1078 Conn *c;
1079 SSHChan *ch;
1080 char *tcpconn2, *buf, *toks[4];
1081 int n, ntok, lev, xconn;
1082 uvlong qidpath;
1083 char path[NETPATHLEN], tcpconn[Numbsz];
1084
1085 threadsetname("writectlproc");
1086 r = a;
1087 qidpath = (uvlong)r->fid->file->aux;
1088 lev = qidpath >> Levshift;
1089 xconn = (qidpath >> Connshift) & Connmask;
1090
1091 c = connections[xconn];
1092 if (c == nil) {
1093 respond(r, "bad connection");
1094 sshlog(c, "bad connection");
1095 threadexits(nil);
1096 }
1097 ch = c->chans[qidpath & Chanmask];
1098
1099 if (r->ifcall.count <= Numbsz)
1100 buf = emalloc9p(Numbsz + 1);
1101 else
1102 buf = emalloc9p(r->ifcall.count + 1);
1103 memmove(buf, r->ifcall.data, r->ifcall.count);
1104 buf[r->ifcall.count] = '\0';
1105
1106 sshdebug(c, "level %d writectl: %s", lev, buf);
1107 ntok = tokenize(buf, toks, nelem(toks));
1108 switch (lev) {
1109 case Connection:
1110 if (strcmp(toks[0], "id") == 0) { /* was for sshswitch */
1111 if (ntok < 2)
1112 respexit(c, r, buf, "bad id request");
1113 strncpy(c->idstring, toks[1], sizeof c->idstring);
1114 sshdebug(c, "id %s", toks[1]);
1115 break;
1116 }
1117 if (strcmp(toks[0], "connect") == 0) {
1118 if (ntok < 2)
1119 respexit(c, r, buf, "bad connect request");
1120 /*
1121 * should use dial(2) instead of doing it by hand.
1122 */
1123 memset(tcpconn, '\0', sizeof(tcpconn));
1124 pread(c->ctlfd, tcpconn, sizeof tcpconn, 0);
1125 dialbyhand(c, ntok, toks);
1126
1127 c->role = Client;
1128 /* Override the PKA list; we can take any in */
1129 pkas[0] = &rsa_pka;
1130 pkas[1] = &dss_pka;
1131 pkas[2] = nil;
1132 tcpconn2 = estrdup9p(tcpconn);
1133
1134 /* swap id strings, negotiate crypto */
1135 if (dohandshake(c, tcpconn2) < 0) {
1136 sshlog(c, "connect handshake failed: "
1137 "tcp conn %s", tcpconn2);
1138 free(tcpconn2);
1139 respexit(c, r, buf, "connect handshake failed");
1140 }
1141 free(tcpconn2);
1142 keymbox.state = Empty;
1143 nbsendul(keymbox.mchan, 1);
1144 break;
1145 }
1146
1147 if (c->state == Closed || c->state == Closing)
1148 respexit(c, r, buf, "connection closed");
1149 if (strcmp(toks[0], "ssh-userauth") == 0)
1150 userauth(c, r, buf, ntok, toks);
1151 else if (strcmp(toks[0], "ssh-connection") == 0) {
1152 /* your ad here */
1153 } else if (strcmp(toks[0], "hangup") == 0) {
1154 if (c->rpid >= 0)
1155 threadint(c->rpid);
1156 shutdown(c);
1157 } else if (strcmp(toks[0], "announce") == 0) {
1158 sshdebug(c, "got %s argument for announce", toks[1]);
1159 write(c->ctlfd, r->ifcall.data, r->ifcall.count);
1160 } else if (strcmp(toks[0], "accept") == 0) {
1161 /* should use dial(2) instead of diddling /net/tcp */
1162 memset(tcpconn, '\0', sizeof(tcpconn));
1163 pread(c->ctlfd, tcpconn, sizeof tcpconn, 0);
1164 fprint(c->ctlfd, "accept %s", tcpconn);
1165
1166 c->role = Server;
1167 tcpconn2 = estrdup9p(tcpconn);
1168 /* swap id strings, negotiate crypto */
1169 if (dohandshake(c, tcpconn2) < 0) {
1170 sshlog(c, "accept handshake failed: "
1171 "tcp conn %s", tcpconn2);
1172 free(tcpconn2);
1173 shutdown(c);
1174 respexit(c, r, buf, "accept handshake failed");
1175 }
1176 free(tcpconn2);
1177 } else if (strcmp(toks[0], "reject") == 0) {
1178 memset(tcpconn, '\0', sizeof(tcpconn));
1179 pread(c->ctlfd, tcpconn, sizeof tcpconn, 0);
1180
1181 snprint(path, NETPATHLEN, "%s/tcp/%s/data", mntpt, tcpconn);
1182 c->datafd = open(path, ORDWR);
1183
1184 p = new_packet(c);
1185 add_byte(p, SSH_MSG_DISCONNECT);
1186 add_byte(p, SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT);
1187 add_string(p, toks[2]);
1188 add_string(p, "EN");
1189 n = finish_packet(p);
1190 if (c->dio && c->datafd >= 0)
1191 iowrite(c->dio, c->datafd, p->nlength, n);
1192 free(p);
1193 if (c->ctlfd >= 0)
1194 fprint(c->ctlfd, "reject %s %s", buf, toks[2]);
1195 if (c->rpid >= 0)
1196 threadint(c->rpid);
1197 shutdown(c);
1198 }
1199 break;
1200 case Subchannel:
1201 if (c->state == Closed || c->state == Closing)
1202 respexit(c, r, buf, "channel closed");
1203 if (strcmp(toks[0], "connect") == 0) {
1204 p = new_packet(c);
1205 add_byte(p, SSH_MSG_CHANNEL_OPEN);
1206 sshdebug(c, "chan writectl: connect %s",
1207 ntok > 1? toks[1]: "session");
1208 add_string(p, ntok > 1? toks[1]: "session");
1209 add_uint32(p, ch->id);
1210 add_uint32(p, Maxpayload);
1211 add_uint32(p, Maxrpcbuf);
1212 /* more stuff if it's an x11 session */
1213 n = finish_packet(p);
1214 iowrite(c->dio, c->datafd, p->nlength, n);
1215 free(p);
1216 qlock(&c->l);
1217 if (ch->otherid == -1)
1218 rsleep(&ch->r);
1219 qunlock(&c->l);
1220 } else if (strcmp(toks[0], "global") == 0) {
1221 /* your ad here */
1222 } else if (strcmp(toks[0], "hangup") == 0) {
1223 if (ch->state != Closed && ch->state != Closing) {
1224 ch->state = Closing;
1225 if (ch->otherid != -1) {
1226 p = new_packet(c);
1227 add_byte(p, SSH_MSG_CHANNEL_CLOSE);
1228 add_uint32(p, ch->otherid);
1229 n = finish_packet(p);
1230 iowrite(c->dio, c->datafd, p->nlength, n);
1231 free(p);
1232 }
1233 qlock(&c->l);
1234 rwakeup(&ch->r);
1235 qunlock(&c->l);
1236 nbsendul(ch->inchan, 1);
1237 nbsendul(ch->reqchan, 1);
1238 }
1239 for (n = 0; n < MAXCONN && (c->chans[n] == nil ||
1240 c->chans[n]->state == Empty ||
1241 c->chans[n]->state == Closing ||
1242 c->chans[n]->state == Closed); ++n)
1243 ;
1244 if (n >= MAXCONN) {
1245 if (c->rpid >= 0)
1246 threadint(c->rpid);
1247 shutdown(c);
1248 }
1249 } else if (strcmp(toks[0], "announce") == 0) {
1250 sshdebug(c, "got argument `%s' for chan announce",
1251 toks[1]);
1252 free(ch->ann);
1253 ch->ann = estrdup9p(toks[1]);
1254 }
1255 break;
1256 }
1257 r->ofcall.count = r->ifcall.count;
1258 r->aux = 0;
1259 respond(r, nil);
1260 free(buf);
1261 threadexits(nil);
1262 }
1263
1264 void
writereqremproc(void * a)1265 writereqremproc(void *a)
1266 {
1267 Req *r;
1268 Packet *p;
1269 Conn *c;
1270 SSHChan *ch;
1271 char *cmd, *q, *buf, *toks[4];
1272 int n, ntok, lev, xconn;
1273 uvlong qidpath;
1274
1275 threadsetname("writereqremproc");
1276 r = a;
1277 qidpath = (uvlong)r->fid->file->aux;
1278 lev = qidpath >> Levshift;
1279 xconn = (qidpath >> Connshift) & Connmask;
1280 c = connections[xconn];
1281 if (c == nil) {
1282 respond(r, "Invalid connection");
1283 threadexits(nil);
1284 }
1285 ch = c->chans[qidpath & Chanmask];
1286 if (r->ifcall.count <= 10)
1287 buf = emalloc9p(10 + 1);
1288 else
1289 buf = emalloc9p(r->ifcall.count + 1);
1290 memmove(buf, r->ifcall.data, r->ifcall.count);
1291 buf[r->ifcall.count] = '\0';
1292 sshdebug(c, "writereqrem: %s", buf);
1293 ntok = tokenize(buf, toks, nelem(toks));
1294
1295 if (lev == Top) {
1296 free(keymbox.msg);
1297 keymbox.msg = buf;
1298 nbsendul(keymbox.mchan, 1);
1299 r->ofcall.count = r->ifcall.count;
1300 respexit(c, r, nil, nil);
1301 }
1302
1303 r->ofcall.count = r->ifcall.count;
1304 if (c->state == Closed || c->state == Closing ||
1305 ch->state == Closed || ch->state == Closing)
1306 respexit(c, r, buf, nil);
1307
1308 p = new_packet(c);
1309 if (strcmp(toks[0], "success") == 0) {
1310 add_byte(p, SSH_MSG_CHANNEL_SUCCESS);
1311 add_uint32(p, ch->otherid);
1312 } else if (strcmp(toks[0], "failure") == 0) {
1313 add_byte(p, SSH_MSG_CHANNEL_FAILURE);
1314 add_uint32(p, ch->otherid);
1315 } else if (strcmp(toks[0], "close") == 0) {
1316 ch->state = Closing;
1317 add_byte(p, SSH_MSG_CHANNEL_CLOSE);
1318 add_uint32(p, ch->otherid);
1319 } else if (strcmp(toks[0], "shell") == 0) {
1320 ch->state = Established;
1321 /*
1322 * Some servers *cough*OpenSSH*cough* don't seem to be able
1323 * to intelligently handle a shell with no pty.
1324 */
1325 add_byte(p, SSH_MSG_CHANNEL_REQUEST);
1326 add_uint32(p, ch->otherid);
1327 add_string(p, "pty-req");
1328 add_byte(p, 0);
1329 if (ntok == 1)
1330 add_string(p, "dumb");
1331 else
1332 add_string(p, toks[1]);
1333 add_uint32(p, 0);
1334 add_uint32(p, 0);
1335 add_uint32(p, 0);
1336 add_uint32(p, 0);
1337 add_string(p, "");
1338 n = finish_packet(p);
1339 iowrite(c->dio, c->datafd, p->nlength, n);
1340 init_packet(p);
1341 p->c = c;
1342 add_byte(p, SSH_MSG_CHANNEL_REQUEST);
1343 add_uint32(p, ch->otherid);
1344 add_string(p, "shell");
1345 add_byte(p, 0);
1346 sshdebug(c, "sending shell request: rlength=%lud twindow=%lud",
1347 p->rlength, ch->twindow);
1348 } else if (strcmp(toks[0], "exec") == 0) {
1349 ch->state = Established;
1350 add_byte(p, SSH_MSG_CHANNEL_REQUEST);
1351 add_uint32(p, ch->otherid);
1352 add_string(p, "exec");
1353 add_byte(p, 0);
1354
1355 cmd = emalloc9p(Bigbufsz);
1356 q = seprint(cmd, cmd+Bigbufsz, "%s", toks[1]);
1357 for (n = 2; n < ntok; ++n) {
1358 q = seprint(q, cmd+Bigbufsz, " %q", toks[n]);
1359 if (q == nil)
1360 break;
1361 }
1362 add_string(p, cmd);
1363 free(cmd);
1364 } else
1365 respexit(c, r, buf, "bad request command");
1366 n = finish_packet(p);
1367 iowrite(c->dio, c->datafd, p->nlength, n);
1368 free(p);
1369 respexit(c, r, buf, nil);
1370 }
1371
1372 void
writedataproc(void * a)1373 writedataproc(void *a)
1374 {
1375 Req *r;
1376 Packet *p;
1377 Conn *c;
1378 SSHChan *ch;
1379 int n, xconn;
1380 uvlong qidpath;
1381
1382 threadsetname("writedataproc");
1383 r = a;
1384 qidpath = (uvlong)r->fid->file->aux;
1385 xconn = (qidpath >> Connshift) & Connmask;
1386 c = connections[xconn];
1387 if (c == nil) {
1388 respond(r, "Invalid connection");
1389 threadexits(nil);
1390 }
1391 ch = c->chans[qidpath & Chanmask];
1392
1393 p = new_packet(c);
1394 add_byte(p, SSH_MSG_CHANNEL_DATA);
1395 hnputl(p->payload+1, ch->otherid);
1396 p->rlength += 4;
1397 add_block(p, r->ifcall.data, r->ifcall.count);
1398 n = finish_packet(p);
1399
1400 if (ch->sent + p->rlength > ch->twindow) {
1401 qlock(&ch->xmtlock);
1402 while (ch->sent + p->rlength > ch->twindow)
1403 rsleep(&ch->xmtrendez);
1404 qunlock(&ch->xmtlock);
1405 }
1406 iowrite(c->dio, c->datafd, p->nlength, n);
1407 respexit(c, r, p, nil);
1408 }
1409
1410 /*
1411 * Although this is named stclunk, it's attached to the destroyfid
1412 * member of the Srv struct. It turns out there's no member
1413 * called clunk. But if there are no other references, a 9P Tclunk
1414 * will end up calling destroyfid.
1415 */
1416 void
stclunk(Fid * f)1417 stclunk(Fid *f)
1418 {
1419 Packet *p;
1420 Conn *c;
1421 SSHChan *sc;
1422 int n, lev, cnum, chnum;
1423 uvlong qidpath;
1424
1425 threadsetname("stclunk");
1426 if (f == nil || f->file == nil)
1427 return;
1428 qidpath = (uvlong)f->file->aux;
1429 lev = qidpath >> Levshift;
1430 cnum = (qidpath >> Connshift) & Connmask;
1431 chnum = qidpath & Chanmask;
1432 c = connections[cnum];
1433 sshdebug(c, "got clunk on file: %#llux %d %d %d: %s",
1434 qidpath, lev, cnum, chnum, f->file->name);
1435 /* qidpath test implies conn 0, chan 0 */
1436 if (lev == Top && qidpath == Qreqrem) {
1437 if (keymbox.state != Empty) {
1438 keymbox.state = Empty;
1439 // nbsendul(keymbox.mchan, 1);
1440 }
1441 keymbox.msg = nil;
1442 return;
1443 }
1444
1445 if (c == nil)
1446 return;
1447 if (lev == Connection && (qidpath & Qtypemask) == Qctl &&
1448 (c->state == Opening || c->state == Negotiating ||
1449 c->state == Authing)) {
1450 for (n = 0; n < MAXCONN && (!c->chans[n] ||
1451 c->chans[n]->state == Empty ||
1452 c->chans[n]->state == Closed ||
1453 c->chans[n]->state == Closing); ++n)
1454 ;
1455 if (n >= MAXCONN) {
1456 if (c->rpid >= 0)
1457 threadint(c->rpid);
1458 shutdown(c);
1459 }
1460 return;
1461 }
1462
1463 sc = c->chans[chnum];
1464 if (lev != Subchannel)
1465 return;
1466 if ((qidpath & Qtypemask) == Qlisten && sc->state == Listening) {
1467 qlock(&c->l);
1468 if (sc->state != Closed) {
1469 sc->state = Closed;
1470 chanclose(sc->inchan);
1471 chanclose(sc->reqchan);
1472 }
1473 qunlock(&c->l);
1474 } else if ((qidpath & Qtypemask) == Qdata && sc->state != Empty &&
1475 sc->state != Closed && sc->state != Closing) {
1476 if (f->file != sc->data && f->file != sc->request) {
1477 sshlog(c, "great evil is upon us; destroying a fid "
1478 "we didn't create");
1479 return;
1480 }
1481
1482 p = new_packet(c);
1483 add_byte(p, SSH_MSG_CHANNEL_CLOSE);
1484 hnputl(p->payload+1, sc->otherid);
1485 p->rlength += 4;
1486 n = finish_packet(p);
1487 sc->state = Closing;
1488 iowrite(c->dio, c->datafd, p->nlength, n);
1489 free(p);
1490
1491 qlock(&c->l);
1492 rwakeup(&sc->r);
1493 qunlock(&c->l);
1494 nbsendul(sc->inchan, 1);
1495 nbsendul(sc->reqchan, 1);
1496 }
1497 for (n = 0; n < MAXCONN && (!c->chans[n] ||
1498 c->chans[n]->state == Empty || c->chans[n]->state == Closed ||
1499 c->chans[n]->state == Closing); ++n)
1500 ;
1501 if (n >= MAXCONN) {
1502 if (c->rpid >= 0)
1503 threadint(c->rpid);
1504 shutdown(c);
1505 }
1506 }
1507
1508 void
stflush(Req * r)1509 stflush(Req *r)
1510 {
1511 Req *or;
1512 uvlong qidpath;
1513
1514 threadsetname("stflush");
1515 or = r->oldreq;
1516 qidpath = (uvlong)or->fid->file->aux;
1517 sshdebug(nil, "got flush on file %#llux %lld %lld %lld: %s %#p",
1518 argv0, qidpath, qidpath >> Levshift,
1519 (qidpath >> Connshift) & Connmask, qidpath & Chanmask,
1520 or->fid->file->name, or->aux);
1521 if (!or->aux)
1522 respond(or, "interrupted");
1523 else if (or->ifcall.type == Topen && (qidpath & Qtypemask) == Qlisten ||
1524 or->ifcall.type == Tread && (qidpath & Qtypemask) == Qdata &&
1525 (qidpath >> Levshift) == Subchannel ||
1526 or->ifcall.type == Tread && (qidpath & Qtypemask) == Qreqrem)
1527 threadint((uintptr)or->aux);
1528 else {
1529 threadkill((uintptr)or->aux);
1530 or->aux = 0;
1531 respond(or, "interrupted");
1532 }
1533 respond(r, nil);
1534 }
1535
1536 void
filedup(Req * r,File * src)1537 filedup(Req *r, File *src)
1538 {
1539 r->ofcall.qid = src->qid;
1540 closefile(r->fid->file);
1541 r->fid->file = src;
1542 incref(src);
1543 }
1544
1545 Conn *
alloc_conn(void)1546 alloc_conn(void)
1547 {
1548 int slevconn, i, s, firstnil;
1549 char buf[Numbsz];
1550 Conn *c;
1551 static QLock aclock;
1552
1553 qlock(&aclock);
1554 firstnil = -1;
1555 for (i = 0; i < MAXCONN; ++i) {
1556 if (connections[i] == nil) {
1557 if (firstnil == -1)
1558 firstnil = i;
1559 continue;
1560 }
1561 s = connections[i]->state;
1562 if (s == Empty || s == Closed)
1563 break;
1564 }
1565 if (i >= MAXCONN) {
1566 if (firstnil == -1) { /* all slots in use? */
1567 qunlock(&aclock);
1568 return nil;
1569 }
1570 /* no reusable slots, allocate a new Conn */
1571 connections[firstnil] = emalloc9p(sizeof(Conn));
1572 memset(connections[firstnil], 0, sizeof(Conn));
1573 i = firstnil;
1574 }
1575
1576 c = connections[i];
1577 memset(&c->r, '\0', sizeof(Rendez));
1578 c->r.l = &c->l;
1579 c->dio = ioproc();
1580 c->rio = nil;
1581 c->state = Allocated;
1582 c->role = Server;
1583 c->id = i;
1584 c->stifle = c->poisoned = 0;
1585 c->user = c->service = nil;
1586 c->inseq = c->nchan = c->outseq = 0;
1587 c->cscrypt = c->csmac = c->ctlfd = c->datafd = c->decrypt =
1588 c->encrypt = c->inmac = c->ncscrypt = c->ncsmac =
1589 c->nsccrypt = c->nscmac = c->outmac = c->rpid = c->sccrypt =
1590 c->scmac = c->tcpconn = -1;
1591 if (c->e) {
1592 mpfree(c->e);
1593 c->e = nil;
1594 }
1595 if (c->x) {
1596 mpfree(c->x);
1597 c->x = nil;
1598 }
1599
1600 snprint(buf, sizeof buf, "%d", i);
1601 if (c->dir == nil) {
1602 slevconn = Connection << Levshift | i << Connshift;
1603 c->dir = createfile(rootfile, buf, uid, 0555|DMDIR,
1604 (void *)(slevconn | Qroot));
1605 c->clonefile = createfile(c->dir, "clone", uid, 0666,
1606 (void *)(slevconn | Qclone));
1607 c->ctlfile = createfile(c->dir, "ctl", uid, 0666,
1608 (void *)(slevconn | Qctl));
1609 c->datafile = createfile(c->dir, "data", uid, 0666,
1610 (void *)(slevconn | Qdata));
1611 c->listenfile = createfile(c->dir, "listen", uid, 0666,
1612 (void *)(slevconn | Qlisten));
1613 c->localfile = createfile(c->dir, "local", uid, 0444,
1614 (void *)(slevconn | Qlocal));
1615 c->remotefile = createfile(c->dir, "remote", uid, 0444,
1616 (void *)(slevconn | Qreqrem));
1617 c->statusfile = createfile(c->dir, "status", uid, 0444,
1618 (void *)(slevconn | Qstatus));
1619 c->tcpfile = createfile(c->dir, "tcp", uid, 0444,
1620 (void *)(slevconn | Qtcp));
1621 }
1622 // c->skexinit = c->rkexinit = nil;
1623 c->got_sessid = 0;
1624 c->otherid = nil;
1625 c->inik = c->outik = nil;
1626 c->s2ccs = c->c2scs = c->enccs = c->deccs = nil;
1627 qunlock(&aclock);
1628 return c;
1629 }
1630
1631 SSHChan *
alloc_chan(Conn * c)1632 alloc_chan(Conn *c)
1633 {
1634 int cnum, slcn;
1635 char buf[Numbsz];
1636 Plist *p, *next;
1637 SSHChan *sc;
1638
1639 if (c->nchan >= MAXCONN)
1640 return nil;
1641 qlock(&c->l);
1642 cnum = c->nchan;
1643 if (c->chans[cnum] == nil) {
1644 c->chans[cnum] = emalloc9p(sizeof(SSHChan));
1645 memset(c->chans[cnum], 0, sizeof(SSHChan));
1646 }
1647 sc = c->chans[cnum];
1648 snprint(buf, sizeof buf, "%d", cnum);
1649 memset(&sc->r, '\0', sizeof(Rendez));
1650 sc->r.l = &c->l;
1651 sc->id = cnum;
1652 sc->state = Empty;
1653 sc->conn = c->id;
1654 sc->otherid = sc->waker = -1;
1655 sc->sent = sc->twindow = sc->rwindow = sc->inrqueue = 0;
1656 sc->ann = nil;
1657 sc->lreq = nil;
1658
1659 if (sc->dir == nil) {
1660 slcn = Subchannel << Levshift | c->id << Connshift | cnum;
1661 sc->dir = createfile(c->dir, buf, uid, 0555|DMDIR,
1662 (void *)(slcn | Qroot));
1663 sc->ctl = createfile(sc->dir, "ctl", uid, 0666,
1664 (void *)(slcn | Qctl));
1665 sc->data = createfile(sc->dir, "data", uid, 0666,
1666 (void *)(slcn | Qdata));
1667 sc->listen = createfile(sc->dir, "listen", uid, 0666,
1668 (void *)(slcn | Qlisten));
1669 sc->request = createfile(sc->dir, "request", uid, 0666,
1670 (void *)(slcn | Qreqrem));
1671 sc->status = createfile(sc->dir, "status", uid, 0444,
1672 (void *)(slcn | Qstatus));
1673 sc->tcp = createfile(sc->dir, "tcp", uid, 0444,
1674 (void *)(slcn | Qtcp));
1675 }
1676 c->nchan++;
1677
1678 for (; sc->reqq != nil; sc->reqq = next) {
1679 p = sc->reqq;
1680 next = p->next;
1681 free(p->pack);
1682 free(p);
1683 }
1684 sc->dataq = sc->datatl = sc->reqtl = nil;
1685
1686 if (sc->inchan)
1687 chanfree(sc->inchan);
1688 sc->inchan = chancreate(4, 0);
1689
1690 if (sc->reqchan)
1691 chanfree(sc->reqchan);
1692 sc->reqchan = chancreate(4, 0);
1693
1694 memset(&sc->xmtrendez, '\0', sizeof(Rendez));
1695 sc->xmtrendez.l = &sc->xmtlock;
1696 qunlock(&c->l);
1697 return sc;
1698 }
1699
1700 static int
readlineio(Conn *,Ioproc * io,int fd,char * buf,int size)1701 readlineio(Conn *, Ioproc *io, int fd, char *buf, int size)
1702 {
1703 int n;
1704 char *p;
1705
1706 for (p = buf; p < buf + size - 1; p++) {
1707 n = ioread(io, fd, p, 1);
1708 if (n != 1 || *p == '\n') {
1709 *p = '\0';
1710 break;
1711 }
1712 }
1713 return p - buf;
1714 }
1715
1716 static char *
readremote(Conn * c,Ioproc * io,char * tcpconn)1717 readremote(Conn *c, Ioproc *io, char *tcpconn)
1718 {
1719 int n, remfd;
1720 char *p, *remote;
1721 char path[Arbbufsz], buf[NETPATHLEN];
1722
1723 remote = nil;
1724 snprint(path, sizeof path, "%s/tcp/%s/remote", mntpt, tcpconn);
1725 remfd = ioopen(io, path, OREAD);
1726 if (remfd < 0) {
1727 sshlog(c, "readremote: can't open %s: %r", path);
1728 return nil;
1729 }
1730 n = ioread(io, remfd, buf, sizeof buf - 1);
1731 if (n > 0) {
1732 buf[n] = 0;
1733 p = strchr(buf, '!');
1734 if (p)
1735 *p = 0;
1736 remote = estrdup9p(buf);
1737 }
1738 ioclose(io, remfd);
1739 return remote;
1740 }
1741
1742 static void
sendmyid(Conn * c,Ioproc * io)1743 sendmyid(Conn *c, Ioproc *io)
1744 {
1745 char path[Arbbufsz];
1746
1747 snprint(path, sizeof path, "%s\r\n", MYID);
1748 iowrite(io, c->datafd, path, strlen(path));
1749 }
1750
1751 /* save and tidy up the remote id */
1752 static void
stashremid(Conn * c,char * remid)1753 stashremid(Conn *c, char *remid)
1754 {
1755 char *nl;
1756
1757 if (c->otherid)
1758 free(c->otherid);
1759 c->otherid = estrdup9p(remid);
1760
1761 nl = strchr(c->otherid, '\n');
1762 if (nl)
1763 *nl = '\0';
1764 nl = strchr(c->otherid, '\r');
1765 if (nl)
1766 *nl = '\0';
1767 }
1768
1769 static void
hangupconn(Conn * c)1770 hangupconn(Conn *c)
1771 {
1772 hangup(c->ctlfd);
1773 close(c->ctlfd);
1774 close(c->datafd);
1775 c->ctlfd = c->datafd = -1;
1776 }
1777
1778 #ifdef COEXIST
1779 static int
exchids(Conn * c,Ioproc * io,char * remid,int remsz)1780 exchids(Conn *c, Ioproc *io, char *remid, int remsz)
1781 {
1782 int n;
1783
1784 /*
1785 * exchange versions. server writes id, then reads;
1786 * client reads id then writes (in theory).
1787 */
1788 if (c->role == Server) {
1789 sendmyid(c, io);
1790
1791 n = readlineio(c, io, c->datafd, remid, remsz);
1792 if (n < 5) /* can't be a valid SSH id string */
1793 return -1;
1794 sshdebug(c, "dohandshake: server, got `%s', sent `%s'", remid,
1795 MYID);
1796 } else {
1797 /* client: read server's id */
1798 n = readlineio(c, io, c->datafd, remid, remsz);
1799 if (n < 5) /* can't be a valid SSH id string */
1800 return -1;
1801
1802 sendmyid(c, io);
1803 sshdebug(c, "dohandshake: client, got `%s' sent `%s'", remid, MYID);
1804 if (remid[0] == '\0') {
1805 sshlog(c, "dohandshake: client, empty remote id string;"
1806 " out of sync");
1807 return -1;
1808 }
1809 }
1810 sshdebug(c, "remote id string `%s'", remid);
1811 return 0;
1812 }
1813
1814 /*
1815 * negotiate the protocols.
1816 * We don't do the full negotiation here, because we also have
1817 * to handle a re-negotiation request from the other end.
1818 * So we just kick it off and let the receiver process take it from there.
1819 */
1820 static int
negotiate(Conn * c)1821 negotiate(Conn *c)
1822 {
1823 send_kexinit(c);
1824
1825 qlock(&c->l);
1826 if ((c->role == Client && c->state != Negotiating) ||
1827 (c->role == Server && c->state != Established)) {
1828 sshdebug(c, "awaiting establishment");
1829 rsleep(&c->r);
1830 }
1831 qunlock(&c->l);
1832
1833 if (c->role == Server && c->state != Established ||
1834 c->role == Client && c->state != Negotiating) {
1835 sshdebug(c, "failed to establish");
1836 return -1;
1837 }
1838 sshdebug(c, "established; crypto now on");
1839 return 0;
1840 }
1841
1842 /* this was deferred when trying to make coexistence with v1 work */
1843 static int
deferredinit(Conn * c)1844 deferredinit(Conn *c)
1845 {
1846 char remid[Arbbufsz];
1847 Ioproc *io;
1848
1849 io = ioproc();
1850 /*
1851 * don't bother checking the remote's id string.
1852 * as a client, we can cope with v1 if we don't verify the host key.
1853 */
1854 if (exchids(c, io, remid, sizeof remid) < 0 ||
1855 0 && c->role == Client && strncmp(remid, "SSH-2", 5) != 0 &&
1856 strncmp(remid, "SSH-1.99", 8) != 0) {
1857 /* not a protocol version we know; give up */
1858 closeioproc(io);
1859 hangupconn(c);
1860 return -1;
1861 }
1862 closeioproc(io);
1863 stashremid(c, remid);
1864
1865 c->state = Initting;
1866
1867 /* start the reader thread */
1868 if (c->rpid < 0)
1869 c->rpid = threadcreate(reader, c, Defstk);
1870
1871 return negotiate(c);
1872 }
1873
1874 int
dohandshake(Conn * c,char * tcpconn)1875 dohandshake(Conn *c, char *tcpconn)
1876 {
1877 int tcpdfd;
1878 char *remote;
1879 char path[Arbbufsz];
1880 Ioproc *io;
1881
1882 io = ioproc();
1883
1884 /* read tcp conn's remote address into c->remote */
1885 remote = readremote(c, io, tcpconn);
1886 if (remote) {
1887 free(c->remote);
1888 c->remote = remote;
1889 }
1890
1891 /* open tcp conn's data file */
1892 c->tcpconn = atoi(tcpconn);
1893 snprint(path, sizeof path, "%s/tcp/%s/data", mntpt, tcpconn);
1894 tcpdfd = ioopen(io, path, ORDWR);
1895 closeioproc(io);
1896 if (tcpdfd < 0) {
1897 sshlog(c, "dohandshake: can't open %s: %r", path);
1898 return -1;
1899 }
1900 c->datafd = tcpdfd; /* underlying tcp data descriptor */
1901
1902 return deferredinit(c);
1903 }
1904 #endif /* COEXIST */
1905
1906 int
dohandshake(Conn * c,char * tcpconn)1907 dohandshake(Conn *c, char *tcpconn)
1908 {
1909 int fd, n;
1910 char *p, *othid;
1911 char path[Arbbufsz], buf[NETPATHLEN];
1912 Ioproc *io;
1913
1914 io = ioproc();
1915 snprint(path, sizeof path, "%s/tcp/%s/remote", mntpt, tcpconn);
1916 fd = ioopen(io, path, OREAD);
1917 n = ioread(io, fd, buf, sizeof buf - 1);
1918 if (n > 0) {
1919 buf[n] = 0;
1920 p = strchr(buf, '!');
1921 if (p)
1922 *p = 0;
1923 free(c->remote);
1924 c->remote = estrdup9p(buf);
1925 }
1926 ioclose(io, fd);
1927
1928 snprint(path, sizeof path, "%s/tcp/%s/data", mntpt, tcpconn);
1929 fd = ioopen(io, path, ORDWR);
1930 if (fd < 0) {
1931 closeioproc(io);
1932 return -1;
1933 }
1934 c->datafd = fd;
1935
1936 /* exchange versions--we're only doing SSH2, unfortunately */
1937
1938 snprint(path, sizeof path, "%s\r\n", MYID);
1939 if (c->idstring && c->idstring[0])
1940 strncpy(path, c->idstring, sizeof path);
1941 else {
1942 iowrite(io, fd, path, strlen(path));
1943 p = path;
1944 n = 0;
1945 do {
1946 if (ioread(io, fd, p, 1) < 0) {
1947 fprint(2, "%s: short read in ID exchange: %r\n",
1948 argv0);
1949 break;
1950 }
1951 ++n;
1952 } while (*p++ != '\n');
1953 if (n < 5) { /* can't be a valid SSH id string */
1954 close(fd);
1955 goto err;
1956 }
1957 *p = 0;
1958 }
1959 sshdebug(c, "id string `%s'", path);
1960 if (c->idstring[0] == '\0' &&
1961 strncmp(path, "SSH-2", 5) != 0 &&
1962 strncmp(path, "SSH-1.99", 8) != 0) {
1963 /* not a protocol version we know; give up */
1964 ioclose(io, fd);
1965 goto err;
1966 }
1967 closeioproc(io);
1968
1969 if (c->otherid)
1970 free(c->otherid);
1971 c->otherid = othid = estrdup9p(path);
1972 for (n = strlen(othid) - 1; othid[n] == '\r' || othid[n] == '\n'; --n)
1973 othid[n] = '\0';
1974 c->state = Initting;
1975
1976 /* start the reader thread */
1977 if (c->rpid < 0)
1978 c->rpid = threadcreate(reader, c, Defstk);
1979
1980 /*
1981 * negotiate the protocols
1982 * We don't do the full negotiation here, because we also have
1983 * to handle a re-negotiation request from the other end. So
1984 * we just kick it off and let the receiver process take it from there.
1985 */
1986
1987 send_kexinit(c);
1988
1989 qlock(&c->l);
1990 if ((c->role == Client && c->state != Negotiating) ||
1991 (c->role == Server && c->state != Established))
1992 rsleep(&c->r);
1993 qunlock(&c->l);
1994 if (c->role == Server && c->state != Established ||
1995 c->role == Client && c->state != Negotiating)
1996 return -1;
1997 return 0;
1998 err:
1999 /* should use hangup in dial(2) instead of diddling /net/tcp */
2000 snprint(path, sizeof path, "%s/tcp/%s/ctl", mntpt, tcpconn);
2001 fd = ioopen(io, path, OWRITE);
2002 iowrite(io, fd, "hangup", 6);
2003 ioclose(io, fd);
2004 closeioproc(io);
2005 return -1;
2006 }
2007
2008 void
send_kexinit(Conn * c)2009 send_kexinit(Conn *c)
2010 {
2011 Packet *ptmp;
2012 char *buf, *p, *e;
2013 int i, msglen;
2014
2015 sshdebug(c, "initializing kexinit packet");
2016 if (c->skexinit != nil)
2017 free(c->skexinit);
2018 c->skexinit = new_packet(c);
2019
2020 buf = emalloc9p(Bigbufsz);
2021 buf[0] = (uchar)SSH_MSG_KEXINIT;
2022
2023 add_packet(c->skexinit, buf, 1);
2024 for (i = 0; i < 16; ++i)
2025 buf[i] = fastrand();
2026
2027 add_packet(c->skexinit, buf, 16); /* cookie */
2028 e = buf + Bigbufsz - 1;
2029 p = seprint(buf, e, "%s", kexes[0]->name);
2030 for (i = 1; i < nelem(kexes); ++i)
2031 p = seprint(p, e, ",%s", kexes[i]->name);
2032 sshdebug(c, "sent KEX algs: %s", buf);
2033
2034 add_string(c->skexinit, buf); /* Key exchange */
2035 if (pkas[0] == nil)
2036 add_string(c->skexinit, "");
2037 else{
2038 p = seprint(buf, e, "%s", pkas[0]->name);
2039 for (i = 1; i < nelem(pkas) && pkas[i] != nil; ++i)
2040 p = seprint(p, e, ",%s", pkas[i]->name);
2041 sshdebug(c, "sent host key algs: %s", buf);
2042 add_string(c->skexinit, buf); /* server's key algs */
2043 }
2044
2045 p = seprint(buf, e, "%s", cryptos[0]->name);
2046 for (i = 1; i < nelem(cryptos); ++i)
2047 p = seprint(p, e, ",%s", cryptos[i]->name);
2048 sshdebug(c, "sent crypto algs: %s", buf);
2049
2050 add_string(c->skexinit, buf); /* c->s crypto */
2051 add_string(c->skexinit, buf); /* s->c crypto */
2052 p = seprint(buf, e, "%s", macnames[0]);
2053 for (i = 1; i < nelem(macnames); ++i)
2054 p = seprint(p, e, ",%s", macnames[i]);
2055 sshdebug(c, "sent MAC algs: %s", buf);
2056
2057 add_string(c->skexinit, buf); /* c->s mac */
2058 add_string(c->skexinit, buf); /* s->c mac */
2059 add_string(c->skexinit, "none"); /* c->s compression */
2060 add_string(c->skexinit, "none"); /* s->c compression */
2061 add_string(c->skexinit, ""); /* c->s languages */
2062 add_string(c->skexinit, ""); /* s->c languages */
2063 memset(buf, 0, 5);
2064 add_packet(c->skexinit, buf, 5);
2065
2066 ptmp = new_packet(c);
2067 memmove(ptmp, c->skexinit, sizeof(Packet));
2068 msglen = finish_packet(ptmp);
2069
2070 if (c->dio && c->datafd >= 0)
2071 iowrite(c->dio, c->datafd, ptmp->nlength, msglen);
2072 free(ptmp);
2073 free(buf);
2074 }
2075
2076 static void
establish(Conn * c)2077 establish(Conn *c)
2078 {
2079 qlock(&c->l);
2080 c->state = Established;
2081 rwakeup(&c->r);
2082 qunlock(&c->l);
2083 }
2084
2085 static int
negotiating(Conn * c,Packet * p,Packet * p2,char * buf,int size)2086 negotiating(Conn *c, Packet *p, Packet *p2, char *buf, int size)
2087 {
2088 int i, n;
2089
2090 USED(size);
2091 switch (p->payload[0]) {
2092 case SSH_MSG_DISCONNECT:
2093 if (debug) {
2094 get_string(p, p->payload + 5, buf, Arbbufsz, nil);
2095 sshdebug(c, "got disconnect: %s", buf);
2096 }
2097 return -1;
2098 case SSH_MSG_NEWKEYS:
2099 /*
2100 * If we're just updating, go straight to
2101 * established, otherwise wait for auth'n.
2102 */
2103 i = c->encrypt;
2104 memmove(c->c2siv, c->nc2siv, SHA1dlen*2);
2105 memmove(c->s2civ, c->ns2civ, SHA1dlen*2);
2106 memmove(c->c2sek, c->nc2sek, SHA1dlen*2);
2107 memmove(c->s2cek, c->ns2cek, SHA1dlen*2);
2108 memmove(c->c2sik, c->nc2sik, SHA1dlen*2);
2109 memmove(c->s2cik, c->ns2cik, SHA1dlen*2);
2110 c->cscrypt = c->ncscrypt;
2111 c->sccrypt = c->nsccrypt;
2112 c->csmac = c->ncsmac;
2113 c->scmac = c->nscmac;
2114 c->c2scs = cryptos[c->cscrypt]->init(c, 0);
2115 c->s2ccs = cryptos[c->sccrypt]->init(c, 1);
2116 if (c->role == Server) {
2117 c->encrypt = c->sccrypt;
2118 c->decrypt = c->cscrypt;
2119 c->outmac = c->scmac;
2120 c->inmac = c->csmac;
2121 c->enccs = c->s2ccs;
2122 c->deccs = c->c2scs;
2123 c->outik = c->s2cik;
2124 c->inik = c->c2sik;
2125 } else{
2126 c->encrypt = c->cscrypt;
2127 c->decrypt = c->sccrypt;
2128 c->outmac = c->csmac;
2129 c->inmac = c->scmac;
2130 c->enccs = c->c2scs;
2131 c->deccs = c->s2ccs;
2132 c->outik = c->c2sik;
2133 c->inik = c->s2cik;
2134 }
2135 sshdebug(c, "using %s for encryption and %s for decryption",
2136 cryptos[c->encrypt]->name, cryptos[c->decrypt]->name);
2137 qlock(&c->l);
2138 if (i != -1)
2139 c->state = Established;
2140 if (c->role == Client)
2141 rwakeup(&c->r);
2142 qunlock(&c->l);
2143 break;
2144 case SSH_MSG_KEXDH_INIT:
2145 kexes[c->kexalg]->serverkex(c, p);
2146 break;
2147 case SSH_MSG_KEXDH_REPLY:
2148 init_packet(p2);
2149 p2->c = c;
2150 if (kexes[c->kexalg]->clientkex2(c, p) < 0) {
2151 add_byte(p2, SSH_MSG_DISCONNECT);
2152 add_byte(p2, SSH_DISCONNECT_KEY_EXCHANGE_FAILED);
2153 add_string(p2, "Key exchange failure");
2154 add_string(p2, "");
2155 n = finish_packet(p2);
2156 iowrite(c->rio, c->datafd, p2->nlength, n);
2157 shutdown(c);
2158 free(p);
2159 free(p2);
2160 closeioproc(c->rio);
2161 c->rio = nil;
2162 c->rpid = -1;
2163
2164 qlock(&c->l);
2165 rwakeup(&c->r);
2166 qunlock(&c->l);
2167
2168 sshlog(c, "key exchange failure");
2169 threadexits(nil);
2170 }
2171 add_byte(p2, SSH_MSG_NEWKEYS);
2172 n = finish_packet(p2);
2173 iowrite(c->rio, c->datafd, p2->nlength, n);
2174 qlock(&c->l);
2175 rwakeup(&c->r);
2176 qunlock(&c->l);
2177 break;
2178 case SSH_MSG_SERVICE_REQUEST:
2179 get_string(p, p->payload + 1, buf, Arbbufsz, nil);
2180 sshdebug(c, "got service request: %s", buf);
2181 if (strcmp(buf, "ssh-userauth") == 0 ||
2182 strcmp(buf, "ssh-connection") == 0) {
2183 init_packet(p2);
2184 p2->c = c;
2185 sshdebug(c, "connection");
2186 add_byte(p2, SSH_MSG_SERVICE_ACCEPT);
2187 add_string(p2, buf);
2188 n = finish_packet(p2);
2189 iowrite(c->rio, c->datafd, p2->nlength, n);
2190 c->state = Authing;
2191 } else{
2192 init_packet(p2);
2193 p2->c = c;
2194 add_byte(p2, SSH_MSG_DISCONNECT);
2195 add_byte(p2, SSH_DISCONNECT_SERVICE_NOT_AVAILABLE);
2196 add_string(p2, "Unknown service type");
2197 add_string(p2, "");
2198 n = finish_packet(p2);
2199 iowrite(c->rio, c->datafd, p2->nlength, n);
2200 return -1;
2201 }
2202 break;
2203 case SSH_MSG_SERVICE_ACCEPT:
2204 get_string(p, p->payload + 1, buf, Arbbufsz, nil);
2205 if (c->service && strcmp(c->service, "ssh-userauth") == 0) {
2206 free(c->service);
2207 c->service = estrdup9p("ssh-connection");
2208 }
2209 sshdebug(c, "got service accept: %s: responding with %s %s",
2210 buf, c->user, c->service);
2211 n = client_auth(c, c->rio);
2212 c->state = Authing;
2213 if (n < 0) {
2214 qlock(&c->l);
2215 rwakeup(&c->r);
2216 qunlock(&c->l);
2217 }
2218 break;
2219 }
2220 return 0;
2221 }
2222
2223 static void
nochans(Conn * c,Packet * p,Packet * p2)2224 nochans(Conn *c, Packet *p, Packet *p2)
2225 {
2226 int n;
2227
2228 init_packet(p2);
2229 p2->c = c;
2230 add_byte(p2, SSH_MSG_CHANNEL_OPEN_FAILURE);
2231 add_block(p2, p->payload + 5, 4);
2232 hnputl(p2->payload + p2->rlength - 1, 4);
2233 p2->rlength += 4;
2234 add_string(p2, "No available channels");
2235 add_string(p2, "EN");
2236 n = finish_packet(p2);
2237 iowrite(c->rio, c->datafd, p2->nlength, n);
2238 }
2239
2240 static int
established(Conn * c,Packet * p,Packet * p2,char * buf,int size)2241 established(Conn *c, Packet *p, Packet *p2, char *buf, int size)
2242 {
2243 int i, n, cnum;
2244 uchar *q;
2245 Plist *pl;
2246 SSHChan *ch;
2247
2248 USED(size);
2249 if (debug > 1) {
2250 sshdebug(c, "in Established state, got:");
2251 dump_packet(p);
2252 }
2253 switch (p->payload[0]) {
2254 case SSH_MSG_DISCONNECT:
2255 if (debug) {
2256 get_string(p, p->payload + 5, buf, Arbbufsz, nil);
2257 sshdebug(c, "got disconnect: %s", buf);
2258 }
2259 return -1;
2260 case SSH_MSG_IGNORE:
2261 case SSH_MSG_UNIMPLEMENTED:
2262 break;
2263 case SSH_MSG_DEBUG:
2264 if (debug || p->payload[1]) {
2265 get_string(p, p->payload + 2, buf, Arbbufsz, nil);
2266 sshdebug(c, "got debug message: %s", buf);
2267 }
2268 break;
2269 case SSH_MSG_KEXINIT:
2270 send_kexinit(c);
2271 if (c->rkexinit)
2272 free(c->rkexinit);
2273 c->rkexinit = new_packet(c);
2274 memmove(c->rkexinit, p, sizeof(Packet));
2275 if (validatekex(c, p) < 0) {
2276 sshdebug(c, "kex crypto algorithm mismatch (Established)");
2277 return -1;
2278 }
2279 sshdebug(c, "using %s Kex algorithm and %s PKA",
2280 kexes[c->kexalg]->name, pkas[c->pkalg]->name);
2281 c->state = Negotiating;
2282 break;
2283 case SSH_MSG_GLOBAL_REQUEST:
2284 case SSH_MSG_REQUEST_SUCCESS:
2285 case SSH_MSG_REQUEST_FAILURE:
2286 break;
2287 case SSH_MSG_CHANNEL_OPEN:
2288 q = get_string(p, p->payload + 1, buf, Arbbufsz, nil);
2289 sshdebug(c, "searching for a listener for channel type %s", buf);
2290 ch = alloc_chan(c);
2291 if (ch == nil) {
2292 nochans(c, p, p2);
2293 break;
2294 }
2295
2296 sshdebug(c, "alloced channel %d for listener", ch->id);
2297 qlock(&c->l);
2298 ch->otherid = nhgetl(q);
2299 ch->twindow = nhgetl(q+4);
2300 sshdebug(c, "got lock in channel open");
2301 for (i = 0; i < c->nchan; ++i)
2302 if (c->chans[i] && c->chans[i]->state == Listening &&
2303 c->chans[i]->ann &&
2304 strcmp(c->chans[i]->ann, buf) == 0)
2305 break;
2306 if (i >= c->nchan) {
2307 sshdebug(c, "no listener: sleeping");
2308 ch->state = Opening;
2309 if (ch->ann)
2310 free(ch->ann);
2311 ch->ann = estrdup9p(buf);
2312 sshdebug(c, "waiting for someone to announce %s", ch->ann);
2313 rsleep(&ch->r);
2314 } else{
2315 sshdebug(c, "found listener on channel %d", ch->id);
2316 c->chans[i]->waker = ch->id;
2317 rwakeup(&c->chans[i]->r);
2318 }
2319 qunlock(&c->l);
2320 break;
2321 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
2322 cnum = nhgetl(p->payload + 1);
2323 ch = c->chans[cnum];
2324 qlock(&c->l);
2325 ch->otherid = nhgetl(p->payload+5);
2326 ch->twindow = nhgetl(p->payload+9);
2327 rwakeup(&ch->r);
2328 qunlock(&c->l);
2329 break;
2330 case SSH_MSG_CHANNEL_OPEN_FAILURE:
2331 cnum = nhgetl(p->payload + 1);
2332 ch = c->chans[cnum];
2333 qlock(&c->l);
2334 rwakeup(&ch->r);
2335 qunlock(&c->l);
2336 return -1;
2337 case SSH_MSG_CHANNEL_WINDOW_ADJUST:
2338 cnum = nhgetl(p->payload + 1);
2339 ch = c->chans[cnum];
2340 ch->twindow += nhgetl(p->payload + 5);
2341 sshdebug(c, "new twindow for channel: %d: %lud", cnum, ch->twindow);
2342 qlock(&ch->xmtlock);
2343 rwakeup(&ch->xmtrendez);
2344 qunlock(&ch->xmtlock);
2345 break;
2346 case SSH_MSG_CHANNEL_DATA:
2347 case SSH_MSG_CHANNEL_EXTENDED_DATA:
2348 cnum = nhgetl(p->payload + 1);
2349 ch = c->chans[cnum];
2350 pl = emalloc9p(sizeof(Plist));
2351 pl->pack = emalloc9p(sizeof(Packet));
2352 memmove(pl->pack, p, sizeof(Packet));
2353 if (p->payload[0] == SSH_MSG_CHANNEL_DATA) {
2354 pl->rem = nhgetl(p->payload + 5);
2355 pl->st = pl->pack->payload + 9;
2356 } else {
2357 pl->rem = nhgetl(p->payload + 9);
2358 pl->st = pl->pack->payload + 13;
2359 }
2360 pl->next = nil;
2361 if (ch->dataq == nil)
2362 ch->dataq = pl;
2363 else
2364 ch->datatl->next = pl;
2365 ch->datatl = pl;
2366 ch->inrqueue += pl->rem;
2367 nbsendul(ch->inchan, 1);
2368 break;
2369 case SSH_MSG_CHANNEL_EOF:
2370 cnum = nhgetl(p->payload + 1);
2371 ch = c->chans[cnum];
2372 if (ch->state != Closed && ch->state != Closing) {
2373 ch->state = Eof;
2374 nbsendul(ch->inchan, 1);
2375 nbsendul(ch->reqchan, 1);
2376 }
2377 break;
2378 case SSH_MSG_CHANNEL_CLOSE:
2379 cnum = nhgetl(p->payload + 1);
2380 ch = c->chans[cnum];
2381 if (ch->state != Closed && ch->state != Closing) {
2382 init_packet(p2);
2383 p2->c = c;
2384 add_byte(p2, SSH_MSG_CHANNEL_CLOSE);
2385 hnputl(p2->payload + 1, ch->otherid);
2386 p2->rlength += 4;
2387 n = finish_packet(p2);
2388 iowrite(c->rio, c->datafd, p2->nlength, n);
2389 }
2390 qlock(&c->l);
2391 if (ch->state != Closed) {
2392 ch->state = Closed;
2393 rwakeup(&ch->r);
2394 nbsendul(ch->inchan, 1);
2395 nbsendul(ch->reqchan, 1);
2396 chanclose(ch->inchan);
2397 chanclose(ch->reqchan);
2398 }
2399 qunlock(&c->l);
2400 for (i = 0; i < MAXCONN && (!c->chans[i] ||
2401 c->chans[i]->state == Empty || c->chans[i]->state == Closed);
2402 ++i)
2403 ;
2404 if (i >= MAXCONN)
2405 return -1;
2406 break;
2407 case SSH_MSG_CHANNEL_REQUEST:
2408 cnum = nhgetl(p->payload + 1);
2409 ch = c->chans[cnum];
2410 sshdebug(c, "queueing channel request for channel: %d", cnum);
2411 q = get_string(p, p->payload+5, buf, Arbbufsz, nil);
2412 pl = emalloc9p(sizeof(Plist));
2413 pl->pack = emalloc9p(sizeof(Packet));
2414 n = snprint((char *)pl->pack->payload,
2415 Maxpayload, "%s %c", buf, *q? 't': 'f');
2416 sshdebug(c, "request message begins: %s",
2417 (char *)pl->pack->payload);
2418 memmove(pl->pack->payload + n, q + 1, p->rlength - (11 + n-2));
2419 pl->rem = p->rlength - 11 + 2;
2420 pl->st = pl->pack->payload;
2421 pl->next = nil;
2422 if (ch->reqq == nil)
2423 ch->reqq = pl;
2424 else
2425 ch->reqtl->next = pl;
2426 ch->reqtl = pl;
2427 nbsendul(ch->reqchan, 1);
2428 break;
2429 case SSH_MSG_CHANNEL_SUCCESS:
2430 case SSH_MSG_CHANNEL_FAILURE:
2431 default:
2432 break;
2433 }
2434 return 0;
2435 }
2436
2437 static void
bail(Conn * c,Packet * p,Packet * p2,char * sts)2438 bail(Conn *c, Packet *p, Packet *p2, char *sts)
2439 {
2440 shutdown(c);
2441 free(p);
2442 free(p2);
2443 if (c->rio) {
2444 closeioproc(c->rio);
2445 c->rio = nil;
2446 }
2447 c->rpid = -1;
2448 threadexits(sts);
2449 }
2450
2451 static void
reader0(Conn * c,Packet * p,Packet * p2)2452 reader0(Conn *c, Packet *p, Packet *p2)
2453 {
2454 int i, n, nl, np, nm, nb;
2455 char buf[Arbbufsz];
2456
2457 nm = 0;
2458 nb = 4;
2459 if (c->decrypt != -1)
2460 nb = cryptos[c->decrypt]->blklen;
2461 sshdebug(c, "calling read for connection %d, state %d, nb %d, dc %d",
2462 c->id, c->state, nb, c->decrypt);
2463 if ((nl = ioreadn(c->rio, c->datafd, p->nlength, nb)) != nb) {
2464 sshdebug(c, "reader for connection %d exiting, got %d: %r",
2465 c->id, nl);
2466 bail(c, p, p2, "reader exiting");
2467 }
2468 if (c->decrypt != -1)
2469 cryptos[c->decrypt]->decrypt(c->deccs, p->nlength, nb);
2470 p->rlength = nhgetl(p->nlength);
2471 sshdebug(c, "got message length: %ld", p->rlength);
2472 if (p->rlength > Maxpktpay) {
2473 sshdebug(c, "absurd packet length: %ld, unrecoverable decrypt failure",
2474 p->rlength);
2475 bail(c, p, p2, "absurd packet length");
2476 }
2477 np = ioreadn(c->rio, c->datafd, p->nlength + nb, p->rlength + 4 - nb);
2478 if (c->inmac != -1)
2479 nm = ioreadn(c->rio, c->datafd, p->nlength + p->rlength + 4,
2480 SHA1dlen); /* SHA1dlen was magic 20 */
2481 n = nl + np + nm;
2482 if (debug) {
2483 sshdebug(c, "got message of %d bytes %d padding", n, p->pad_len);
2484 if (p->payload[0] > SSH_MSG_CHANNEL_OPEN) {
2485 i = nhgetl(p->payload+1);
2486 if (c->chans[i])
2487 sshdebug(c, " for channel %d win %lud",
2488 i, c->chans[i]->rwindow);
2489 else
2490 sshdebug(c, " for invalid channel %d", i);
2491 }
2492 sshdebug(c, " first byte: %d", p->payload[0]);
2493 }
2494 /* SHA1dlen was magic 20 */
2495 if (np != p->rlength + 4 - nb || c->inmac != -1 && nm != SHA1dlen) {
2496 sshdebug(c, "got EOF/error on connection read: %d %d %r", np, nm);
2497 bail(c, p, p2, "error or eof");
2498 }
2499 p->tlength = n;
2500 p->rlength = n - 4;
2501 if (undo_packet(p) < 0) {
2502 sshdebug(c, "bad packet in connection %d: exiting", c->id);
2503 bail(c, p, p2, "bad packet");
2504 }
2505
2506 if (c->state == Initting) {
2507 if (p->payload[0] != SSH_MSG_KEXINIT) {
2508 sshdebug(c, "missing KEX init packet: %d", p->payload[0]);
2509 bail(c, p, p2, "bad kex");
2510 }
2511 if (c->rkexinit)
2512 free(c->rkexinit);
2513 c->rkexinit = new_packet(c);
2514 memmove(c->rkexinit, p, sizeof(Packet));
2515 if (validatekex(c, p) < 0) {
2516 sshdebug(c, "kex crypto algorithm mismatch (Initting)");
2517 bail(c, p, p2, "bad kex");
2518 }
2519 sshdebug(c, "using %s Kex algorithm and %s PKA",
2520 kexes[c->kexalg]->name, pkas[c->pkalg]->name);
2521 if (c->role == Client)
2522 kexes[c->kexalg]->clientkex1(c, p);
2523 c->state = Negotiating;
2524 } else if (c->state == Negotiating) {
2525 if (negotiating(c, p, p2, buf, sizeof buf) < 0)
2526 bail(c, p, p2, "negotiating");
2527 } else if (c->state == Authing) {
2528 switch (p->payload[0]) {
2529 case SSH_MSG_DISCONNECT:
2530 if (debug) {
2531 get_string(p, p->payload + 5, buf, Arbbufsz, nil);
2532 sshdebug(c, "got disconnect: %s", buf);
2533 }
2534 bail(c, p, p2, "msg disconnect");
2535 case SSH_MSG_USERAUTH_REQUEST:
2536 switch (auth_req(p, c)) {
2537 case 0: /* success */
2538 establish(c);
2539 break;
2540 case 1: /* ok to try again */
2541 case -1: /* failure */
2542 break;
2543 case -2: /* can't happen, now at least */
2544 bail(c, p, p2, "in userauth request");
2545 }
2546 break;
2547 case SSH_MSG_USERAUTH_FAILURE:
2548 qlock(&c->l);
2549 rwakeup(&c->r);
2550 qunlock(&c->l);
2551 break;
2552 case SSH_MSG_USERAUTH_SUCCESS:
2553 establish(c);
2554 break;
2555 case SSH_MSG_USERAUTH_BANNER:
2556 break;
2557 }
2558 } else if (c->state == Established) {
2559 if (established(c, p, p2, buf, sizeof buf) < 0)
2560 bail(c, p, p2, "from established state");
2561 } else {
2562 sshdebug(c, "connection %d in bad state, reader exiting", c->id);
2563 bail(c, p, p2, "bad conn state");
2564 }
2565 }
2566
2567 void
reader(void * a)2568 reader(void *a)
2569 {
2570 Conn *c;
2571 Packet *p, *p2;
2572
2573 threadsetname("reader");
2574 c = a;
2575 c->rpid = threadid();
2576 sshdebug(c, "starting reader for connection %d, pid %d", c->id, c->rpid);
2577 threadsetname("reader");
2578 p = new_packet(c);
2579 p2 = new_packet(c);
2580 c->rio = ioproc();
2581 for(;;)
2582 reader0(c, p, p2);
2583 }
2584
2585 int
validatekex(Conn * c,Packet * p)2586 validatekex(Conn *c, Packet *p)
2587 {
2588 if (c->role == Server)
2589 return validatekexs(p);
2590 else
2591 return validatekexc(p);
2592 }
2593
2594 int
validatekexs(Packet * p)2595 validatekexs(Packet *p)
2596 {
2597 uchar *q;
2598 char *toks[Maxtoks];
2599 int i, j, n;
2600 char *buf;
2601
2602 buf = emalloc9p(Bigbufsz);
2603 q = p->payload + 17;
2604
2605 q = get_string(p, q, buf, Bigbufsz, nil);
2606 sshdebug(nil, "received KEX algs: %s", buf);
2607 n = gettokens(buf, toks, nelem(toks), ",");
2608 for (i = 0; i < n; ++i)
2609 for (j = 0; j < nelem(kexes); ++j)
2610 if (strcmp(toks[i], kexes[j]->name) == 0)
2611 goto foundk;
2612 sshdebug(nil, "kex algs not in kexes");
2613 free(buf);
2614 return -1;
2615 foundk:
2616 p->c->kexalg = j;
2617
2618 q = get_string(p, q, buf, Bigbufsz, nil);
2619 sshdebug(nil, "received host key algs: %s", buf);
2620 n = gettokens(buf, toks, nelem(toks), ",");
2621 for (i = 0; i < n; ++i)
2622 for (j = 0; j < nelem(pkas) && pkas[j] != nil; ++j)
2623 if (strcmp(toks[i], pkas[j]->name) == 0)
2624 goto foundpka;
2625 sshdebug(nil, "host key algs not in pkas");
2626 free(buf);
2627 return -1;
2628 foundpka:
2629 p->c->pkalg = j;
2630
2631 q = get_string(p, q, buf, Bigbufsz, nil);
2632 sshdebug(nil, "received C2S crypto algs: %s", buf);
2633 n = gettokens(buf, toks, nelem(toks), ",");
2634 for (i = 0; i < n; ++i)
2635 for (j = 0; j < nelem(cryptos); ++j)
2636 if (strcmp(toks[i], cryptos[j]->name) == 0)
2637 goto foundc1;
2638 sshdebug(nil, "c2s crypto algs not in cryptos");
2639 free(buf);
2640 return -1;
2641 foundc1:
2642 p->c->ncscrypt = j;
2643
2644 q = get_string(p, q, buf, Bigbufsz, nil);
2645 sshdebug(nil, "received S2C crypto algs: %s", buf);
2646 n = gettokens(buf, toks, nelem(toks), ",");
2647 for (i = 0; i < n; ++i)
2648 for (j = 0; j < nelem(cryptos); ++j)
2649 if (strcmp(toks[i], cryptos[j]->name) == 0)
2650 goto foundc2;
2651 sshdebug(nil, "s2c crypto algs not in cryptos");
2652 free(buf);
2653 return -1;
2654 foundc2:
2655 p->c->nsccrypt = j;
2656
2657 q = get_string(p, q, buf, Bigbufsz, nil);
2658 sshdebug(nil, "received C2S MAC algs: %s", buf);
2659 n = gettokens(buf, toks, nelem(toks), ",");
2660 for (i = 0; i < n; ++i)
2661 for (j = 0; j < nelem(macnames); ++j)
2662 if (strcmp(toks[i], macnames[j]) == 0)
2663 goto foundm1;
2664 sshdebug(nil, "c2s mac algs not in cryptos");
2665 free(buf);
2666 return -1;
2667 foundm1:
2668 p->c->ncsmac = j;
2669
2670 q = get_string(p, q, buf, Bigbufsz, nil);
2671 sshdebug(nil, "received S2C MAC algs: %s", buf);
2672 n = gettokens(buf, toks, nelem(toks), ",");
2673 for (i = 0; i < n; ++i)
2674 for (j = 0; j < nelem(macnames); ++j)
2675 if (strcmp(toks[i], macnames[j]) == 0)
2676 goto foundm2;
2677 sshdebug(nil, "s2c mac algs not in cryptos");
2678 free(buf);
2679 return -1;
2680 foundm2:
2681 p->c->nscmac = j;
2682
2683 q = get_string(p, q, buf, Bigbufsz, nil);
2684 q = get_string(p, q, buf, Bigbufsz, nil);
2685 q = get_string(p, q, buf, Bigbufsz, nil);
2686 q = get_string(p, q, buf, Bigbufsz, nil);
2687 free(buf);
2688 if (*q)
2689 return 1;
2690 return 0;
2691 }
2692
2693 int
validatekexc(Packet * p)2694 validatekexc(Packet *p)
2695 {
2696 uchar *q;
2697 char *toks[Maxtoks];
2698 int i, j, n;
2699 char *buf;
2700
2701 buf = emalloc9p(Bigbufsz);
2702 q = p->payload + 17;
2703 q = get_string(p, q, buf, Bigbufsz, nil);
2704 n = gettokens(buf, toks, nelem(toks), ",");
2705 for (j = 0; j < nelem(kexes); ++j)
2706 for (i = 0; i < n; ++i)
2707 if (strcmp(toks[i], kexes[j]->name) == 0)
2708 goto foundk;
2709 free(buf);
2710 return -1;
2711 foundk:
2712 p->c->kexalg = j;
2713
2714 q = get_string(p, q, buf, Bigbufsz, nil);
2715 n = gettokens(buf, toks, nelem(toks), ",");
2716 for (j = 0; j < nelem(pkas) && pkas[j] != nil; ++j)
2717 for (i = 0; i < n; ++i)
2718 if (strcmp(toks[i], pkas[j]->name) == 0)
2719 goto foundpka;
2720 free(buf);
2721 return -1;
2722 foundpka:
2723 p->c->pkalg = j;
2724
2725 q = get_string(p, q, buf, Bigbufsz, nil);
2726 n = gettokens(buf, toks, nelem(toks), ",");
2727 for (j = 0; j < nelem(cryptos); ++j)
2728 for (i = 0; i < n; ++i)
2729 if (strcmp(toks[i], cryptos[j]->name) == 0)
2730 goto foundc1;
2731 free(buf);
2732 return -1;
2733 foundc1:
2734 p->c->ncscrypt = j;
2735 q = get_string(p, q, buf, Bigbufsz, nil);
2736 n = gettokens(buf, toks, nelem(toks), ",");
2737 for (j = 0; j < nelem(cryptos); ++j)
2738 for (i = 0; i < n; ++i)
2739 if (strcmp(toks[i], cryptos[j]->name) == 0)
2740 goto foundc2;
2741 free(buf);
2742 return -1;
2743 foundc2:
2744 p->c->nsccrypt = j;
2745
2746 q = get_string(p, q, buf, Bigbufsz, nil);
2747 n = gettokens(buf, toks, nelem(toks), ",");
2748 for (j = 0; j < nelem(macnames); ++j)
2749 for (i = 0; i < n; ++i)
2750 if (strcmp(toks[i], macnames[j]) == 0)
2751 goto foundm1;
2752 free(buf);
2753 return -1;
2754 foundm1:
2755 p->c->ncsmac = j;
2756
2757 q = get_string(p, q, buf, Bigbufsz, nil);
2758 n = gettokens(buf, toks, nelem(toks), ",");
2759 for (j = 0; j < nelem(macnames); ++j)
2760 for (i = 0; i < n; ++i)
2761 if (strcmp(toks[i], macnames[j]) == 0)
2762 goto foundm2;
2763 free(buf);
2764 return -1;
2765 foundm2:
2766 p->c->nscmac = j;
2767
2768 q = get_string(p, q, buf, Bigbufsz, nil);
2769 q = get_string(p, q, buf, Bigbufsz, nil);
2770 q = get_string(p, q, buf, Bigbufsz, nil);
2771 q = get_string(p, q, buf, Bigbufsz, nil);
2772 free(buf);
2773 return *q != 0;
2774 }
2775
2776 int
memrandom(void * p,int n)2777 memrandom(void *p, int n)
2778 {
2779 uchar *cp;
2780
2781 for (cp = (uchar*)p; n > 0; n--)
2782 *cp++ = fastrand();
2783 return 0;
2784 }
2785
2786 /*
2787 * create a change uid capability
2788 */
2789 char*
mkcap(char * from,char * to)2790 mkcap(char *from, char *to)
2791 {
2792 int fd, fromtosz;
2793 char *cap, *key;
2794 uchar rand[SHA1dlen], hash[SHA1dlen];
2795
2796 fd = open("#¤/caphash", OWRITE);
2797 if (fd < 0)
2798 sshlog(nil, "can't open #¤/caphash: %r");
2799
2800 /* create the capability */
2801 fromtosz = strlen(from) + 1 + strlen(to) + 1;
2802 cap = emalloc9p(fromtosz + sizeof(rand)*3 + 1);
2803 snprint(cap, fromtosz + sizeof(rand)*3 + 1, "%s@%s", from, to);
2804 memrandom(rand, sizeof(rand));
2805 key = cap + fromtosz;
2806 enc64(key, sizeof(rand)*3, rand, sizeof(rand));
2807
2808 /* hash the capability */
2809 hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
2810
2811 /* give the kernel the hash */
2812 key[-1] = '@';
2813 sshdebug(nil, "writing `%.*s' to caphash", SHA1dlen, hash);
2814 if (write(fd, hash, SHA1dlen) != SHA1dlen) {
2815 close(fd);
2816 free(cap);
2817 return nil;
2818 }
2819 close(fd);
2820 return cap;
2821 }
2822
2823 /*
2824 * ask keyfs (assumes we are on an auth server)
2825 */
2826 static AuthInfo *
keyfsauth(char * me,char * user,char * pw,char * key1,char * key2)2827 keyfsauth(char *me, char *user, char *pw, char *key1, char *key2)
2828 {
2829 int fd;
2830 char path[Arbpathlen];
2831 AuthInfo *ai;
2832
2833 if (passtokey(key1, pw) == 0)
2834 return nil;
2835
2836 snprint(path, Arbpathlen, "/mnt/keys/%s/key", user);
2837 if ((fd = open(path, OREAD)) < 0) {
2838 werrstr("Invalid user %s", user);
2839 return nil;
2840 }
2841 if (read(fd, key2, DESKEYLEN) != DESKEYLEN) {
2842 close(fd);
2843 werrstr("Password mismatch 1");
2844 return nil;
2845 }
2846 close(fd);
2847
2848 if (memcmp(key1, key2, DESKEYLEN) != 0) {
2849 werrstr("Password mismatch 2");
2850 return nil;
2851 }
2852
2853 ai = emalloc9p(sizeof(AuthInfo));
2854 ai->cuid = estrdup9p(user);
2855 ai->suid = estrdup9p(me);
2856 ai->cap = mkcap(me, user);
2857 ai->nsecret = 0;
2858 ai->secret = (uchar *)estrdup9p("");
2859 return ai;
2860 }
2861
2862 static void
userauthfailed(Packet * p2)2863 userauthfailed(Packet *p2)
2864 {
2865 add_byte(p2, SSH_MSG_USERAUTH_FAILURE);
2866 add_string(p2, "password,publickey");
2867 add_byte(p2, 0);
2868 }
2869
2870 static int
authreqpk(Packet * p,Packet * p2,Conn * c,char * user,uchar * q,char * alg,char * blob,char * sig,char * service,char * me)2871 authreqpk(Packet *p, Packet *p2, Conn *c, char *user, uchar *q,
2872 char *alg, char *blob, char *sig, char *service, char *me)
2873 {
2874 int n, thisway, nblob, nsig;
2875 char method[32];
2876
2877 sshdebug(c, "auth_req publickey for user %s", user);
2878 thisway = *q == '\0';
2879 q = get_string(p, q+1, alg, Arbpathlen, nil);
2880 q = get_string(p, q, blob, Blobsz, &nblob);
2881 if (thisway) {
2882 /*
2883 * Should really check to see if this user can
2884 * be authed this way.
2885 */
2886 for (n = 0; n < nelem(pkas) && pkas[n] != nil &&
2887 strcmp(pkas[n]->name, alg) != 0; ++n)
2888 ;
2889 if (n >= nelem(pkas) || pkas[n] == nil) {
2890 userauthfailed(p2);
2891 return -1;
2892 }
2893 add_byte(p2, SSH_MSG_USERAUTH_PK_OK);
2894 add_string(p2, alg);
2895 add_block(p2, blob, nblob);
2896 return 1;
2897 }
2898
2899 get_string(p, q, sig, Blobsz, &nsig);
2900 for (n = 0; n < nelem(pkas) && pkas[n] != nil &&
2901 strcmp(pkas[n]->name, alg) != 0; ++n)
2902 ;
2903 if (n >= nelem(pkas) || pkas[n] == nil) {
2904 userauthfailed(p2);
2905 return -1;
2906 }
2907
2908 add_block(p2, c->sessid, SHA1dlen);
2909 add_byte(p2, SSH_MSG_USERAUTH_REQUEST);
2910 add_string(p2, user);
2911 add_string(p2, service);
2912 add_string(p2, method);
2913 add_byte(p2, 1);
2914 add_string(p2, alg);
2915 add_block(p2, blob, nblob);
2916 if (pkas[n]->verify(c, p2->payload, p2->rlength - 1, user, sig, nsig)
2917 == 0) {
2918 init_packet(p2);
2919 p2->c = c;
2920 sshlog(c, "public key login failed");
2921 userauthfailed(p2);
2922 return -1;
2923 }
2924 free(c->cap);
2925 c->cap = mkcap(me, user);
2926 init_packet(p2);
2927 p2->c = c;
2928 sshlog(c, "logged in by public key");
2929 add_byte(p2, SSH_MSG_USERAUTH_SUCCESS);
2930 return 0;
2931 }
2932
2933 int
auth_req(Packet * p,Conn * c)2934 auth_req(Packet *p, Conn *c)
2935 {
2936 int n, ret;
2937 char *alg, *blob, *sig, *service, *me, *user, *pw, *path;
2938 char key1[DESKEYLEN], key2[DESKEYLEN], method[32];
2939 uchar *q;
2940 AuthInfo *ai;
2941 Packet *p2;
2942
2943 service = emalloc9p(Arbpathlen);
2944 me = emalloc9p(Arbpathlen);
2945 user = emalloc9p(Arbpathlen);
2946 pw = emalloc9p(Arbpathlen);
2947 alg = emalloc9p(Arbpathlen);
2948 path = emalloc9p(Arbpathlen);
2949 blob = emalloc9p(Blobsz);
2950 sig = emalloc9p(Blobsz);
2951 ret = -1; /* failure is default */
2952
2953 q = get_string(p, p->payload + 1, user, Arbpathlen, nil);
2954 free(c->user);
2955 c->user = estrdup9p(user);
2956 q = get_string(p, q, service, Arbpathlen, nil);
2957 q = get_string(p, q, method, sizeof method, nil);
2958 sshdebug(c, "got userauth request: %s %s %s", user, service, method);
2959
2960 readfile("/dev/user", me, Arbpathlen);
2961
2962 p2 = new_packet(c);
2963 if (strcmp(method, "publickey") == 0)
2964 ret = authreqpk(p, p2, c, user, q, alg, blob, sig, service, me);
2965 else if (strcmp(method, "password") == 0) {
2966 get_string(p, q + 1, pw, Arbpathlen, nil);
2967 // sshdebug(c, "%s", pw); /* bad idea to log passwords */
2968 sshdebug(c, "auth_req password");
2969 if (kflag)
2970 ai = keyfsauth(me, user, pw, key1, key2);
2971 else
2972 ai = auth_userpasswd(user, pw);
2973 if (ai == nil) {
2974 sshlog(c, "login failed: %r");
2975 userauthfailed(p2);
2976 } else {
2977 sshdebug(c, "auth successful: cuid %s suid %s cap %s",
2978 ai->cuid, ai->suid, ai->cap);
2979 free(c->cap);
2980 if (strcmp(user, me) == 0)
2981 c->cap = estrdup9p("n/a");
2982 else
2983 c->cap = estrdup9p(ai->cap);
2984 sshlog(c, "logged in by password");
2985 add_byte(p2, SSH_MSG_USERAUTH_SUCCESS);
2986 auth_freeAI(ai);
2987 ret = 0;
2988 }
2989 } else
2990 userauthfailed(p2);
2991
2992 n = finish_packet(p2);
2993 iowrite(c->dio, c->datafd, p2->nlength, n);
2994
2995 free(service);
2996 free(me);
2997 free(user);
2998 free(pw);
2999 free(alg);
3000 free(blob);
3001 free(sig);
3002 free(path);
3003 free(p2);
3004 return ret;
3005 }
3006
3007 int
client_auth(Conn * c,Ioproc * io)3008 client_auth(Conn *c, Ioproc *io)
3009 {
3010 Packet *p2, *p3, *p4;
3011 char *r, *s;
3012 mpint *ek, *nk;
3013 int i, n;
3014
3015 sshdebug(c, "client_auth");
3016 if (!c->password && !c->authkey)
3017 return -1;
3018
3019 p2 = new_packet(c);
3020 add_byte(p2, SSH_MSG_USERAUTH_REQUEST);
3021 add_string(p2, c->user);
3022 add_string(p2, c->service);
3023 if (c->password) {
3024 add_string(p2, "password");
3025 add_byte(p2, 0);
3026 add_string(p2, c->password);
3027 sshdebug(c, "client_auth using password for svc %s", c->service);
3028 } else {
3029 sshdebug(c, "client_auth trying rsa public key");
3030 add_string(p2, "publickey");
3031 add_byte(p2, 1);
3032 add_string(p2, "ssh-rsa");
3033
3034 r = strstr(c->authkey, " ek=");
3035 s = strstr(c->authkey, " n=");
3036 if (!r || !s) {
3037 shutdown(c);
3038 free(p2);
3039 sshdebug(c, "client_auth no rsa key");
3040 return -1;
3041 }
3042 ek = strtomp(r+4, nil, 16, nil);
3043 nk = strtomp(s+3, nil, 16, nil);
3044
3045 p3 = new_packet(c);
3046 add_string(p3, "ssh-rsa");
3047 add_mp(p3, ek);
3048 add_mp(p3, nk);
3049 add_block(p2, p3->payload, p3->rlength-1);
3050
3051 p4 = new_packet(c);
3052 add_block(p4, c->sessid, SHA1dlen);
3053 add_byte(p4, SSH_MSG_USERAUTH_REQUEST);
3054 add_string(p4, c->user);
3055 add_string(p4, c->service);
3056 add_string(p4, "publickey");
3057 add_byte(p4, 1);
3058 add_string(p4, "ssh-rsa");
3059 add_block(p4, p3->payload, p3->rlength-1);
3060 mpfree(ek);
3061 mpfree(nk);
3062 free(p3);
3063
3064 for (i = 0; pkas[i] && strcmp("ssh-rsa", pkas[i]->name) != 0;
3065 ++i)
3066 ;
3067 sshdebug(c, "client_auth rsa signing alg %d: %r", i);
3068 if ((p3 = pkas[i]->sign(c, p4->payload, p4->rlength-1)) == nil) {
3069 sshdebug(c, "client_auth rsa signing failed: %r");
3070 free(p4);
3071 free(p2);
3072 return -1;
3073 }
3074 add_block(p2, p3->payload, p3->rlength-1);
3075 free(p3);
3076 free(p4);
3077 }
3078
3079 n = finish_packet(p2);
3080 if (writeio(io, c->datafd, p2->nlength, n) != n)
3081 sshdebug(c, "client_auth write failed: %r");
3082 free(p2);
3083 return 0;
3084 }
3085
3086 /* should use auth_getkey or something similar */
3087 char *
factlookup(int nattr,int nreq,char * attrs[])3088 factlookup(int nattr, int nreq, char *attrs[])
3089 {
3090 Biobuf *bp;
3091 char *buf, *toks[Maxtoks], *res, *q;
3092 int ntok, nmatch, maxmatch;
3093 int i, j;
3094
3095 res = nil;
3096 bp = Bopen("/mnt/factotum/ctl", OREAD);
3097 if (bp == nil)
3098 return nil;
3099 maxmatch = 0;
3100 while (buf = Brdstr(bp, '\n', 1)) {
3101 q = estrdup9p(buf);
3102 ntok = gettokens(buf, toks, nelem(toks), " ");
3103 nmatch = 0;
3104 for (i = 0; i < nattr; ++i) {
3105 for (j = 0; j < ntok; ++j)
3106 if (strcmp(attrs[i], toks[j]) == 0) {
3107 ++nmatch;
3108 break;
3109 }
3110 if (i < nreq && j >= ntok)
3111 break;
3112 }
3113 if (i >= nattr && nmatch > maxmatch) {
3114 free(res);
3115 res = q;
3116 maxmatch = nmatch;
3117 } else
3118 free(q);
3119 free(buf);
3120 }
3121 Bterm(bp);
3122 return res;
3123 }
3124
3125 void
shutdown(Conn * c)3126 shutdown(Conn *c)
3127 {
3128 Plist *p;
3129 SSHChan *sc;
3130 int i, ostate;
3131
3132 sshdebug(c, "shutting down connection %d", c->id);
3133 ostate = c->state;
3134 if (c->clonefile->ref <= 2 && c->ctlfile->ref <= 2 &&
3135 c->datafile->ref <= 2 && c->listenfile->ref <= 2 &&
3136 c->localfile->ref <= 2 && c->remotefile->ref <= 2 &&
3137 c->statusfile->ref <= 2)
3138 c->state = Closed;
3139 else {
3140 if (c->state != Closed)
3141 c->state = Closing;
3142 sshdebug(c, "clone %ld ctl %ld data %ld listen %ld "
3143 "local %ld remote %ld status %ld",
3144 c->clonefile->ref, c->ctlfile->ref, c->datafile->ref,
3145 c->listenfile->ref, c->localfile->ref, c->remotefile->ref,
3146 c->statusfile->ref);
3147 }
3148 if (ostate == Closed || ostate == Closing) {
3149 c->state = Closed;
3150 return;
3151 }
3152 if (c->role == Server && c->remote)
3153 sshlog(c, "closing connection");
3154 hangupconn(c);
3155 if (c->dio) {
3156 closeioproc(c->dio);
3157 c->dio = nil;
3158 }
3159
3160 c->decrypt = -1;
3161 c->inmac = -1;
3162 c->nchan = 0;
3163 free(c->otherid);
3164 free(c->s2ccs);
3165 c->s2ccs = nil;
3166 free(c->c2scs);
3167 c->c2scs = nil;
3168 free(c->remote);
3169 c->remote = nil;
3170 if (c->x) {
3171 mpfree(c->x);
3172 c->x = nil;
3173 }
3174 if (c->e) {
3175 mpfree(c->e);
3176 c->e = nil;
3177 }
3178 free(c->user);
3179 c->user = nil;
3180 free(c->service);
3181 c->service = nil;
3182 c->otherid = nil;
3183 qlock(&c->l);
3184 rwakeupall(&c->r);
3185 qunlock(&c->l);
3186 for (i = 0; i < MAXCONN; ++i) {
3187 sc = c->chans[i];
3188 if (sc == nil)
3189 continue;
3190 free(sc->ann);
3191 sc->ann = nil;
3192 if (sc->state != Empty && sc->state != Closed) {
3193 sc->state = Closed;
3194 sc->lreq = nil;
3195 while (sc->dataq != nil) {
3196 p = sc->dataq;
3197 sc->dataq = p->next;
3198 free(p->pack);
3199 free(p);
3200 }
3201 while (sc->reqq != nil) {
3202 p = sc->reqq;
3203 sc->reqq = p->next;
3204 free(p->pack);
3205 free(p);
3206 }
3207 qlock(&c->l);
3208 rwakeupall(&sc->r);
3209 nbsendul(sc->inchan, 1);
3210 nbsendul(sc->reqchan, 1);
3211 chanclose(sc->inchan);
3212 chanclose(sc->reqchan);
3213 qunlock(&c->l);
3214 }
3215 }
3216 qlock(&availlck);
3217 rwakeup(&availrend);
3218 qunlock(&availlck);
3219 sshdebug(c, "done processing shutdown of connection %d", c->id);
3220 }
3221