📄 ssh.c
字号:
#include "ssh.h"int cooked = 0; /* user wants cooked mode */int raw = 0; /* console is in raw mode */int crstrip;int interactive = -1;int usemenu = 1;int isatty(int);int rawhack;int forwardagent = 0;char *buildcmd(int, char**);void fromnet(Conn*);void fromstdin(Conn*);void winchanges(Conn*);static void sendwritemsg(Conn *c, char *buf, int n);Cipher *allcipher[] = { &cipherrc4, &cipherblowfish, &cipher3des, &cipherdes, &ciphernone, &ciphertwiddle,};Auth *allauth[] = { &authpassword, &authrsa, &authtis,};char *cipherlist = "blowfish rc4 3des";char *authlist = "rsa password tis";Cipher*findcipher(char *name, Cipher **list, int nlist){ int i; for(i=0; i<nlist; i++) if(strcmp(name, list[i]->name) == 0) return list[i]; error("unknown cipher %s", name); return nil;}Auth*findauth(char *name, Auth **list, int nlist){ int i; for(i=0; i<nlist; i++) if(strcmp(name, list[i]->name) == 0) return list[i]; error("unknown auth %s", name); return nil;}voidusage(void){ fprint(2, "usage: ssh [-CiImPpRr] [-A authlist] [-c cipherlist] [user@]hostname [cmd [args]]\n"); exits("usage");}voidmain(int argc, char **argv){ int i, dowinchange, fd, usepty; char *host, *cmd, *user, *p; char *f[16]; Conn c; Msg *m; fmtinstall('B', mpfmt); fmtinstall('H', encodefmt); atexit(atexitkiller); atexitkill(getpid()); dowinchange = 0; if(getenv("LINES")) dowinchange = 1; usepty = -1; user = nil; ARGBEGIN{ case 'B': /* undocumented, debugging */ doabort = 1; break; case 'D': /* undocumented, debugging */ debuglevel = strtol(EARGF(usage()), nil, 0); break; case 'l': /* deprecated */ case 'u': user = EARGF(usage()); break; case 'a': /* used by Unix scp implementations; we must ignore them. */ case 'x': break; case 'A': authlist = EARGF(usage()); break; case 'C': cooked = 1; break; case 'c': cipherlist = EARGF(usage()); break; case 'f': forwardagent = 1; break; case 'I': interactive = 0; break; case 'i': interactive = 1; break; case 'm': usemenu = 0; break; case 'P': usepty = 0; break; case 'p': usepty = 1; break; case 'R': rawhack = 1; break; case 'r': crstrip = 1; break; default: usage(); }ARGEND if(argc < 1) usage(); host = argv[0]; cmd = nil; if(argc > 1) cmd = buildcmd(argc-1, argv+1); if((p = strchr(host, '@')) != nil){ *p++ = '\0'; user = host; host = p; } if(user == nil) user = getenv("user"); if(user == nil) sysfatal("cannot find user name"); privatefactotum(); if(interactive==-1) interactive = isatty(0); if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0) sysfatal("dialing %s: %r", host); memset(&c, 0, sizeof c); c.interactive = interactive; c.fd[0] = c.fd[1] = fd; c.user = user; c.host = host; setaliases(&c, host); c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", "); c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher); for(i=0; i<c.nokcipher; i++) c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher)); c.nokauth = getfields(authlist, f, nelem(f), 1, ", "); c.okauth = emalloc(sizeof(Auth*)*c.nokauth); for(i=0; i<c.nokauth; i++) c.okauth[i] = findauth(f[i], allauth, nelem(allauth)); sshclienthandshake(&c); if(forwardagent){ if(startagent(&c) < 0) forwardagent = 0; } if(usepty == -1) usepty = cmd==nil; if(usepty) requestpty(&c); if(cmd){ m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd)); putstring(m, cmd); }else m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0); sendmsg(m); fromstdin(&c); rfork(RFNOTEG); /* only fromstdin gets notes */ if(dowinchange) winchanges(&c); fromnet(&c); exits(0);}intisatty(int fd){ char buf[64]; buf[0] = '\0'; fd2path(fd, buf, sizeof buf); if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0) return 1; return 0;}char*buildcmd(int argc, char **argv){ int i, len; char *s, *t; len = argc-1; for(i=0; i<argc; i++) len += strlen(argv[i]); s = emalloc(len+1); t = s; for(i=0; i<argc; i++){ if(i) *t++ = ' '; strcpy(t, argv[i]); t += strlen(t); } return s;}voidfromnet(Conn *c){ int fd, len; char *s, *es, *r, *w; ulong ex; char buf[64]; Msg *m; for(;;){ m = recvmsg(c, -1); if(m == nil) break; switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_EXITSTATUS: ex = getlong(m); if(ex==0) exits(0); sprint(buf, "%lud", ex); exits(buf); case SSH_MSG_DISCONNECT: s = getstring(m); error("disconnect: %s", s); /* * If we ever add reverse port forwarding, we'll have to * revisit this. It assumes that the agent connections are * the only ones. */ case SSH_SMSG_AGENT_OPEN: if(!forwardagent) error("server tried to use agent forwarding"); handleagentopen(m); break; case SSH_MSG_CHANNEL_INPUT_EOF: if(!forwardagent) error("server tried to use agent forwarding"); handleagentieof(m); break; case SSH_MSG_CHANNEL_OUTPUT_CLOSED: if(!forwardagent) error("server tried to use agent forwarding"); handleagentoclose(m); break; case SSH_MSG_CHANNEL_DATA: if(!forwardagent) error("server tried to use agent forwarding"); handleagentmsg(m); break; case SSH_SMSG_STDOUT_DATA: fd = 1; goto Dataout; case SSH_SMSG_STDERR_DATA: fd = 2; goto Dataout; Dataout: len = getlong(m); s = (char*)getbytes(m, len); if(crstrip){ es = s+len; for(r=w=s; r<es; r++) if(*r != '\r') *w++ = *r; len = w-s; } write(fd, s, len); break; } free(m); }} /* * Lifted from telnet.c, con.c */static int consctl = -1;static int outfd1=1, outfd2=2; /* changed during system */static void system(Conn*, char*);/* * turn keyboard raw mode on */static voidrawon(void){ if(raw) return; if(cooked) return; if(consctl < 0) consctl = open("/dev/consctl", OWRITE); if(consctl < 0) return; if(write(consctl, "rawon", 5) != 5) return; raw = 1;}/* * turn keyboard raw mode off */static voidrawoff(void){ if(raw == 0) return; if(consctl < 0) return; if(write(consctl, "rawoff", 6) != 6) return; close(consctl); consctl = -1; raw = 0;}/* * control menu */#define STDHELP "\t(q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"static intmenu(Conn *c){ char buf[1024]; long n; int done; int wasraw; wasraw = raw; if(wasraw) rawoff(); buf[0] = '?'; fprint(2, ">>> "); for(done = 0; !done; ){ n = read(0, buf, sizeof(buf)-1); if(n <= 0) return -1; buf[n] = 0; switch(buf[0]){ case '!': print(buf); system(c, buf+1); print("!\n"); done = 1; break; case 'i': buf[0] = 0x1c; sendwritemsg(c, buf, 1); done = 1; break; case '.': case 'q': done = 1; break; case 'r': crstrip = 1-crstrip; done = 1; break; default: fprint(2, STDHELP); break; } if(!done) fprint(2, ">>> "); } if(wasraw) rawon(); else rawoff(); return buf[0];}static voidsendwritemsg(Conn *c, char *buf, int n){ Msg *m; if(n==0) m = allocmsg(c, SSH_CMSG_EOF, 0); else{ m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n); putlong(m, n); putbytes(m, buf, n); } sendmsg(m);}/* * run a command with the network connection as standard IO */static voidsystem(Conn *c, char *cmd){ int pid; int p; int pfd[2]; int n; int wasconsctl; char buf[4096]; if(pipe(pfd) < 0){ perror("pipe"); return; } outfd1 = outfd2 = pfd[1]; wasconsctl = consctl; close(consctl); consctl = -1; switch(pid = fork()){ case -1: perror("con"); return; case 0: close(pfd[1]); dup(pfd[0], 0); dup(pfd[0], 1); close(c->fd[0]); /* same as c->fd[1] */ close(pfd[0]); if(*cmd) execl("/bin/rc", "rc", "-c", cmd, nil); else execl("/bin/rc", "rc", nil); perror("con"); exits("exec"); break; default: close(pfd[0]); while((n = read(pfd[1], buf, sizeof(buf))) > 0) sendwritemsg(c, buf, n); p = waitpid(); outfd1 = 1; outfd2 = 2; close(pfd[1]); if(p < 0 || p != pid) return; break; } if(wasconsctl >= 0){ consctl = open("/dev/consctl", OWRITE); if(consctl < 0) error("cannot open consctl"); }}static voidcookedcatchint(void*, char *msg){ if(strstr(msg, "interrupt")) noted(NCONT); else if(strstr(msg, "kill")) noted(NDFLT); else noted(NCONT);}static intwasintr(void){ char err[64]; rerrstr(err, sizeof err); return strstr(err, "interrupt") != 0;}voidfromstdin(Conn *c){ int n; char buf[1024]; int pid; int eofs; switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){ case -1: error("fork: %r"); case 0: break; default: atexitkill(pid); return; } atexit(atexitkiller); if(interactive) rawon(); notify(cookedcatchint); eofs = 0; for(;;){ n = read(0, buf, sizeof(buf)); if(n < 0){ if(wasintr()){ if(!raw){ buf[0] = 0x7f; n = 1; }else continue; }else break; } if(n == 0){ if(!c->interactive || ++eofs > 32) break; }else eofs = 0; if(interactive && usemenu && n && memchr(buf, 0x1c, n)) { if(menu(c)=='q'){ sendwritemsg(c, "", 0); exits("quit"); } continue; } if(!raw && n==0){ buf[0] = 0x4; n = 1; } sendwritemsg(c, buf, n); } sendwritemsg(c, "", 0); atexitdont(atexitkiller); exits(nil);}voidwinchanges(Conn *c){ int nrow, ncol, width, height; int pid; switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){ case -1: error("fork: %r"); case 0: break; default: atexitkill(pid); return; } for(;;){ if(readgeom(&nrow, &ncol, &width, &height) < 0) break; sendwindowsize(c, nrow, ncol, width, height); } exits(nil);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -