3 int cooked = 0; /* user wants cooked mode */
4 int raw = 0; /* console is in raw mode */
11 char *buildcmd(int, char**);
13 void fromstdin(Conn*);
14 void winchanges(Conn*);
15 static void sendwritemsg(Conn *c, char *buf, int n);
17 Cipher *allcipher[] = {
32 char *cipherlist = "blowfish rc4 3des";
33 char *authlist = "rsa password tis";
36 findcipher(char *name, Cipher **list, int nlist)
40 for(i=0; i<nlist; i++)
41 if(strcmp(name, list[i]->name) == 0)
43 error("unknown cipher %s", name);
48 findauth(char *name, Auth **list, int nlist)
52 for(i=0; i<nlist; i++)
53 if(strcmp(name, list[i]->name) == 0)
55 error("unknown auth %s", name);
62 fprint(2, "usage: ssh [-CiImPpRr] [-A authlist] [-c cipherlist] [user@]hostname [cmd [args]]\n");
67 main(int argc, char **argv)
69 int i, dowinchange, fd, usepty;
70 char *host, *cmd, *user, *p;
75 fmtinstall('B', mpfmt);
76 fmtinstall('H', encodefmt);
86 case 'B': /* undocumented, debugging */
89 case 'D': /* undocumented, debugging */
90 debuglevel = strtol(EARGF(usage()), nil, 0);
92 case 'l': /* deprecated */
94 user = EARGF(usage());
96 case 'a': /* used by Unix scp implementations; we must ignore them. */
101 authlist = EARGF(usage());
107 cipherlist = EARGF(usage());
144 cmd = buildcmd(argc-1, argv+1);
146 if((p = strchr(host, '@')) != nil){
152 user = getenv("user");
154 sysfatal("cannot find user name");
158 interactive = isatty(0);
160 if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
161 sysfatal("dialing %s: %r", host);
163 memset(&c, 0, sizeof c);
164 c.interactive = interactive;
165 c.fd[0] = c.fd[1] = fd;
168 setaliases(&c, host);
170 c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
171 c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
172 for(i=0; i<c.nokcipher; i++)
173 c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
175 c.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
176 c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
177 for(i=0; i<c.nokauth; i++)
178 c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
180 sshclienthandshake(&c);
183 if(startagent(&c) < 0)
191 m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd));
194 m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
198 rfork(RFNOTEG); /* only fromstdin gets notes */
211 fd2path(fd, buf, sizeof buf);
212 if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
218 buildcmd(int argc, char **argv)
224 for(i=0; i<argc; i++)
225 len += strlen(argv[i]);
228 for(i=0; i<argc; i++){
241 char *s, *es, *r, *w;
254 case SSH_SMSG_EXITSTATUS:
258 sprint(buf, "%lud", ex);
261 case SSH_MSG_DISCONNECT:
263 error("disconnect: %s", s);
266 * If we ever add reverse port forwarding, we'll have to
267 * revisit this. It assumes that the agent connections are
270 case SSH_SMSG_AGENT_OPEN:
272 error("server tried to use agent forwarding");
275 case SSH_MSG_CHANNEL_INPUT_EOF:
277 error("server tried to use agent forwarding");
280 case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
282 error("server tried to use agent forwarding");
283 handleagentoclose(m);
285 case SSH_MSG_CHANNEL_DATA:
287 error("server tried to use agent forwarding");
291 case SSH_SMSG_STDOUT_DATA:
294 case SSH_SMSG_STDERR_DATA:
299 s = (char*)getbytes(m, len);
302 for(r=w=s; r<es; r++)
315 * Lifted from telnet.c, con.c
318 static int consctl = -1;
319 static int outfd1=1, outfd2=2; /* changed during system */
320 static void system(Conn*, char*);
323 * turn keyboard raw mode on
333 consctl = open("/dev/consctl", OWRITE);
336 if(write(consctl, "rawon", 5) != 5)
342 * turn keyboard raw mode off
351 if(write(consctl, "rawoff", 6) != 6)
361 #define STDHELP "\t(q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
377 for(done = 0; !done; ){
378 n = read(0, buf, sizeof(buf)-1);
391 sendwritemsg(c, buf, 1);
418 sendwritemsg(Conn *c, char *buf, int n)
423 m = allocmsg(c, SSH_CMSG_EOF, 0);
425 m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n);
433 * run a command with the network connection as standard IO
436 system(Conn *c, char *cmd)
449 outfd1 = outfd2 = pfd[1];
451 wasconsctl = consctl;
454 switch(pid = fork()){
462 close(c->fd[0]); /* same as c->fd[1] */
465 execl("/bin/rc", "rc", "-c", cmd, nil);
467 execl("/bin/rc", "rc", nil);
473 while((n = read(pfd[1], buf, sizeof(buf))) > 0)
474 sendwritemsg(c, buf, n);
479 if(p < 0 || p != pid)
484 consctl = open("/dev/consctl", OWRITE);
486 error("cannot open consctl");
491 cookedcatchint(void*, char *msg)
493 if(strstr(msg, "interrupt"))
495 else if(strstr(msg, "kill"))
506 rerrstr(err, sizeof err);
507 return strstr(err, "interrupt") != 0;
518 switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
528 atexit(atexitkiller);
532 notify(cookedcatchint);
536 n = read(0, buf, sizeof(buf));
548 if(!c->interactive || ++eofs > 32)
552 if(interactive && usemenu && n && memchr(buf, 0x1c, n)) {
554 sendwritemsg(c, "", 0);
563 sendwritemsg(c, buf, n);
565 sendwritemsg(c, "", 0);
566 atexitdont(atexitkiller);
573 int nrow, ncol, width, height;
576 switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
587 if(readgeom(&nrow, &ncol, &width, &height) < 0)
589 sendwindowsize(c, nrow, ncol, width, height);