163afb9a5SDavid du Colombier /* remote login via ssh v1 */
263afb9a5SDavid du Colombier #include "ssh.h"
363afb9a5SDavid du Colombier
463afb9a5SDavid du Colombier int cooked = 0; /* user wants cooked mode */
563afb9a5SDavid du Colombier int raw = 0; /* console is in raw mode */
663afb9a5SDavid du Colombier int crstrip;
763afb9a5SDavid du Colombier int interactive = -1;
863afb9a5SDavid du Colombier int usemenu = 1;
963afb9a5SDavid du Colombier int isatty(int);
1063afb9a5SDavid du Colombier int rawhack;
1163afb9a5SDavid du Colombier int forwardagent = 0;
1263afb9a5SDavid du Colombier char *buildcmd(int, char**);
1363afb9a5SDavid du Colombier void fromnet(Conn*);
1463afb9a5SDavid du Colombier void fromstdin(Conn*);
1563afb9a5SDavid du Colombier void winchanges(Conn*);
1663afb9a5SDavid du Colombier static void sendwritemsg(Conn *c, char *buf, int n);
1763afb9a5SDavid du Colombier
1863afb9a5SDavid du Colombier /*
1963afb9a5SDavid du Colombier * Lifted from telnet.c, con.c
2063afb9a5SDavid du Colombier */
2163afb9a5SDavid du Colombier static int consctl = -1;
2263afb9a5SDavid du Colombier static int outfd = 1; /* changed during system */
2363afb9a5SDavid du Colombier static void system(Conn*, char*);
2463afb9a5SDavid du Colombier
2563afb9a5SDavid du Colombier Cipher *allcipher[] = {
2663afb9a5SDavid du Colombier &cipherrc4,
2763afb9a5SDavid du Colombier &cipherblowfish,
2863afb9a5SDavid du Colombier &cipher3des,
2963afb9a5SDavid du Colombier &cipherdes,
3063afb9a5SDavid du Colombier &ciphernone,
3163afb9a5SDavid du Colombier &ciphertwiddle,
3263afb9a5SDavid du Colombier };
3363afb9a5SDavid du Colombier
3463afb9a5SDavid du Colombier Auth *allauth[] = {
3563afb9a5SDavid du Colombier &authpassword,
3663afb9a5SDavid du Colombier &authrsa,
3763afb9a5SDavid du Colombier &authtis,
3863afb9a5SDavid du Colombier };
3963afb9a5SDavid du Colombier
4063afb9a5SDavid du Colombier char *cipherlist = "blowfish rc4 3des";
4163afb9a5SDavid du Colombier char *authlist = "rsa password tis";
4263afb9a5SDavid du Colombier
4363afb9a5SDavid du Colombier Cipher*
findcipher(char * name,Cipher ** list,int nlist)4463afb9a5SDavid du Colombier findcipher(char *name, Cipher **list, int nlist)
4563afb9a5SDavid du Colombier {
4663afb9a5SDavid du Colombier int i;
4763afb9a5SDavid du Colombier
4863afb9a5SDavid du Colombier for(i=0; i<nlist; i++)
4963afb9a5SDavid du Colombier if(strcmp(name, list[i]->name) == 0)
5063afb9a5SDavid du Colombier return list[i];
5163afb9a5SDavid du Colombier error("unknown cipher %s", name);
5263afb9a5SDavid du Colombier return nil;
5363afb9a5SDavid du Colombier }
5463afb9a5SDavid du Colombier
5563afb9a5SDavid du Colombier Auth*
findauth(char * name,Auth ** list,int nlist)5663afb9a5SDavid du Colombier findauth(char *name, Auth **list, int nlist)
5763afb9a5SDavid du Colombier {
5863afb9a5SDavid du Colombier int i;
5963afb9a5SDavid du Colombier
6063afb9a5SDavid du Colombier for(i=0; i<nlist; i++)
6163afb9a5SDavid du Colombier if(strcmp(name, list[i]->name) == 0)
6263afb9a5SDavid du Colombier return list[i];
6363afb9a5SDavid du Colombier error("unknown auth %s", name);
6463afb9a5SDavid du Colombier return nil;
6563afb9a5SDavid du Colombier }
6663afb9a5SDavid du Colombier
6763afb9a5SDavid du Colombier void
usage(void)6863afb9a5SDavid du Colombier usage(void)
6963afb9a5SDavid du Colombier {
7063afb9a5SDavid du Colombier fprint(2, "usage: ssh [-CiImPpRr] [-A authlist] [-c cipherlist] [user@]hostname [cmd [args]]\n");
7163afb9a5SDavid du Colombier exits("usage");
7263afb9a5SDavid du Colombier }
7363afb9a5SDavid du Colombier
7463afb9a5SDavid du Colombier void
main(int argc,char ** argv)7563afb9a5SDavid du Colombier main(int argc, char **argv)
7663afb9a5SDavid du Colombier {
7763afb9a5SDavid du Colombier int i, dowinchange, fd, usepty;
7863afb9a5SDavid du Colombier char *host, *cmd, *user, *p;
7963afb9a5SDavid du Colombier char *f[16];
8063afb9a5SDavid du Colombier Conn c;
8163afb9a5SDavid du Colombier Msg *m;
8263afb9a5SDavid du Colombier
8363afb9a5SDavid du Colombier fmtinstall('B', mpfmt);
8463afb9a5SDavid du Colombier fmtinstall('H', encodefmt);
8563afb9a5SDavid du Colombier atexit(atexitkiller);
8663afb9a5SDavid du Colombier atexitkill(getpid());
8763afb9a5SDavid du Colombier
8863afb9a5SDavid du Colombier dowinchange = 0;
8963afb9a5SDavid du Colombier if(getenv("LINES"))
9063afb9a5SDavid du Colombier dowinchange = 1;
9163afb9a5SDavid du Colombier usepty = -1;
9263afb9a5SDavid du Colombier user = nil;
9363afb9a5SDavid du Colombier ARGBEGIN{
9463afb9a5SDavid du Colombier case 'B': /* undocumented, debugging */
9563afb9a5SDavid du Colombier doabort = 1;
9663afb9a5SDavid du Colombier break;
9763afb9a5SDavid du Colombier case 'D': /* undocumented, debugging */
9863afb9a5SDavid du Colombier debuglevel = strtol(EARGF(usage()), nil, 0);
9963afb9a5SDavid du Colombier break;
10063afb9a5SDavid du Colombier case 'l': /* deprecated */
10163afb9a5SDavid du Colombier case 'u':
10263afb9a5SDavid du Colombier user = EARGF(usage());
10363afb9a5SDavid du Colombier break;
10463afb9a5SDavid du Colombier case 'a': /* used by Unix scp implementations; we must ignore them. */
10563afb9a5SDavid du Colombier case 'x':
10663afb9a5SDavid du Colombier break;
10763afb9a5SDavid du Colombier
10863afb9a5SDavid du Colombier case 'A':
10963afb9a5SDavid du Colombier authlist = EARGF(usage());
11063afb9a5SDavid du Colombier break;
11163afb9a5SDavid du Colombier case 'C':
11263afb9a5SDavid du Colombier cooked = 1;
11363afb9a5SDavid du Colombier break;
11463afb9a5SDavid du Colombier case 'c':
11563afb9a5SDavid du Colombier cipherlist = EARGF(usage());
11663afb9a5SDavid du Colombier break;
11763afb9a5SDavid du Colombier case 'f':
11863afb9a5SDavid du Colombier forwardagent = 1;
11963afb9a5SDavid du Colombier break;
12063afb9a5SDavid du Colombier case 'I':
12163afb9a5SDavid du Colombier interactive = 0;
12263afb9a5SDavid du Colombier break;
12363afb9a5SDavid du Colombier case 'i':
12463afb9a5SDavid du Colombier interactive = 1;
12563afb9a5SDavid du Colombier break;
12663afb9a5SDavid du Colombier case 'm':
12763afb9a5SDavid du Colombier usemenu = 0;
12863afb9a5SDavid du Colombier break;
12963afb9a5SDavid du Colombier case 'P':
13063afb9a5SDavid du Colombier usepty = 0;
13163afb9a5SDavid du Colombier break;
13263afb9a5SDavid du Colombier case 'p':
13363afb9a5SDavid du Colombier usepty = 1;
13463afb9a5SDavid du Colombier break;
13563afb9a5SDavid du Colombier case 'R':
13663afb9a5SDavid du Colombier rawhack = 1;
13763afb9a5SDavid du Colombier break;
13863afb9a5SDavid du Colombier case 'r':
13963afb9a5SDavid du Colombier crstrip = 1;
14063afb9a5SDavid du Colombier break;
14163afb9a5SDavid du Colombier default:
14263afb9a5SDavid du Colombier usage();
14363afb9a5SDavid du Colombier }ARGEND
14463afb9a5SDavid du Colombier
14563afb9a5SDavid du Colombier if(argc < 1)
14663afb9a5SDavid du Colombier usage();
14763afb9a5SDavid du Colombier
14863afb9a5SDavid du Colombier host = argv[0];
14963afb9a5SDavid du Colombier
15063afb9a5SDavid du Colombier cmd = nil;
15163afb9a5SDavid du Colombier if(argc > 1)
15263afb9a5SDavid du Colombier cmd = buildcmd(argc-1, argv+1);
15363afb9a5SDavid du Colombier
15463afb9a5SDavid du Colombier if((p = strchr(host, '@')) != nil){
15563afb9a5SDavid du Colombier *p++ = '\0';
15663afb9a5SDavid du Colombier user = host;
15763afb9a5SDavid du Colombier host = p;
15863afb9a5SDavid du Colombier }
15963afb9a5SDavid du Colombier if(user == nil)
16063afb9a5SDavid du Colombier user = getenv("user");
16163afb9a5SDavid du Colombier if(user == nil)
16263afb9a5SDavid du Colombier sysfatal("cannot find user name");
16363afb9a5SDavid du Colombier
16463afb9a5SDavid du Colombier privatefactotum();
16563afb9a5SDavid du Colombier if(interactive==-1)
16663afb9a5SDavid du Colombier interactive = isatty(0);
16763afb9a5SDavid du Colombier
16863afb9a5SDavid du Colombier if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
16963afb9a5SDavid du Colombier sysfatal("dialing %s: %r", host);
17063afb9a5SDavid du Colombier
17163afb9a5SDavid du Colombier memset(&c, 0, sizeof c);
17263afb9a5SDavid du Colombier c.interactive = interactive;
17363afb9a5SDavid du Colombier c.fd[0] = c.fd[1] = fd;
17463afb9a5SDavid du Colombier c.user = user;
17563afb9a5SDavid du Colombier c.host = host;
17663afb9a5SDavid du Colombier setaliases(&c, host);
17763afb9a5SDavid du Colombier
17863afb9a5SDavid du Colombier c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
17963afb9a5SDavid du Colombier c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
18063afb9a5SDavid du Colombier for(i=0; i<c.nokcipher; i++)
18163afb9a5SDavid du Colombier c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
18263afb9a5SDavid du Colombier
18363afb9a5SDavid du Colombier c.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
18463afb9a5SDavid du Colombier c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
18563afb9a5SDavid du Colombier for(i=0; i<c.nokauth; i++)
18663afb9a5SDavid du Colombier c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
18763afb9a5SDavid du Colombier
18863afb9a5SDavid du Colombier sshclienthandshake(&c);
18963afb9a5SDavid du Colombier
19063afb9a5SDavid du Colombier if(forwardagent){
19163afb9a5SDavid du Colombier if(startagent(&c) < 0)
19263afb9a5SDavid du Colombier forwardagent = 0;
19363afb9a5SDavid du Colombier }
19463afb9a5SDavid du Colombier if(usepty == -1)
19563afb9a5SDavid du Colombier usepty = cmd==nil;
19663afb9a5SDavid du Colombier if(usepty)
19763afb9a5SDavid du Colombier requestpty(&c);
19863afb9a5SDavid du Colombier if(cmd){
19963afb9a5SDavid du Colombier m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd));
20063afb9a5SDavid du Colombier putstring(m, cmd);
20163afb9a5SDavid du Colombier }else
20263afb9a5SDavid du Colombier m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
20363afb9a5SDavid du Colombier sendmsg(m);
20463afb9a5SDavid du Colombier
20563afb9a5SDavid du Colombier fromstdin(&c);
20663afb9a5SDavid du Colombier rfork(RFNOTEG); /* only fromstdin gets notes */
20763afb9a5SDavid du Colombier if(dowinchange)
20863afb9a5SDavid du Colombier winchanges(&c);
20963afb9a5SDavid du Colombier fromnet(&c);
21063afb9a5SDavid du Colombier exits(0);
21163afb9a5SDavid du Colombier }
21263afb9a5SDavid du Colombier
21363afb9a5SDavid du Colombier int
isatty(int fd)21463afb9a5SDavid du Colombier isatty(int fd)
21563afb9a5SDavid du Colombier {
21663afb9a5SDavid du Colombier char buf[64];
21763afb9a5SDavid du Colombier
21863afb9a5SDavid du Colombier buf[0] = '\0';
21963afb9a5SDavid du Colombier fd2path(fd, buf, sizeof buf);
22063afb9a5SDavid du Colombier if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
22163afb9a5SDavid du Colombier return 1;
22263afb9a5SDavid du Colombier return 0;
22363afb9a5SDavid du Colombier }
22463afb9a5SDavid du Colombier
22563afb9a5SDavid du Colombier char*
buildcmd(int argc,char ** argv)22663afb9a5SDavid du Colombier buildcmd(int argc, char **argv)
22763afb9a5SDavid du Colombier {
22863afb9a5SDavid du Colombier int i, len;
22963afb9a5SDavid du Colombier char *s, *t;
23063afb9a5SDavid du Colombier
23163afb9a5SDavid du Colombier len = argc-1;
23263afb9a5SDavid du Colombier for(i=0; i<argc; i++)
23363afb9a5SDavid du Colombier len += strlen(argv[i]);
23463afb9a5SDavid du Colombier s = emalloc(len+1);
23563afb9a5SDavid du Colombier t = s;
23663afb9a5SDavid du Colombier for(i=0; i<argc; i++){
23763afb9a5SDavid du Colombier if(i)
23863afb9a5SDavid du Colombier *t++ = ' ';
23963afb9a5SDavid du Colombier strcpy(t, argv[i]);
24063afb9a5SDavid du Colombier t += strlen(t);
24163afb9a5SDavid du Colombier }
24263afb9a5SDavid du Colombier return s;
24363afb9a5SDavid du Colombier }
24463afb9a5SDavid du Colombier
24563afb9a5SDavid du Colombier
24663afb9a5SDavid du Colombier void
fromnet(Conn * c)24763afb9a5SDavid du Colombier fromnet(Conn *c)
24863afb9a5SDavid du Colombier {
24963afb9a5SDavid du Colombier int fd, len;
25063afb9a5SDavid du Colombier char *s, *es, *r, *w;
25163afb9a5SDavid du Colombier ulong ex;
25263afb9a5SDavid du Colombier char buf[64];
25363afb9a5SDavid du Colombier Msg *m;
25463afb9a5SDavid du Colombier
25563afb9a5SDavid du Colombier for(;;){
25663afb9a5SDavid du Colombier m = recvmsg(c, -1);
25763afb9a5SDavid du Colombier if(m == nil)
25863afb9a5SDavid du Colombier break;
25963afb9a5SDavid du Colombier switch(m->type){
26063afb9a5SDavid du Colombier default:
26163afb9a5SDavid du Colombier badmsg(m, 0);
26263afb9a5SDavid du Colombier
26363afb9a5SDavid du Colombier case SSH_SMSG_EXITSTATUS:
26463afb9a5SDavid du Colombier ex = getlong(m);
26563afb9a5SDavid du Colombier if(ex==0)
26663afb9a5SDavid du Colombier exits(0);
26763afb9a5SDavid du Colombier sprint(buf, "%lud", ex);
26863afb9a5SDavid du Colombier exits(buf);
26963afb9a5SDavid du Colombier
27063afb9a5SDavid du Colombier case SSH_MSG_DISCONNECT:
27163afb9a5SDavid du Colombier s = getstring(m);
27263afb9a5SDavid du Colombier error("disconnect: %s", s);
27363afb9a5SDavid du Colombier
27463afb9a5SDavid du Colombier /*
27563afb9a5SDavid du Colombier * If we ever add reverse port forwarding, we'll have to
27663afb9a5SDavid du Colombier * revisit this. It assumes that the agent connections are
27763afb9a5SDavid du Colombier * the only ones.
27863afb9a5SDavid du Colombier */
27963afb9a5SDavid du Colombier case SSH_SMSG_AGENT_OPEN:
28063afb9a5SDavid du Colombier if(!forwardagent)
28163afb9a5SDavid du Colombier error("server tried to use agent forwarding");
28263afb9a5SDavid du Colombier handleagentopen(m);
28363afb9a5SDavid du Colombier break;
28463afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_INPUT_EOF:
28563afb9a5SDavid du Colombier if(!forwardagent)
28663afb9a5SDavid du Colombier error("server tried to use agent forwarding");
28763afb9a5SDavid du Colombier handleagentieof(m);
28863afb9a5SDavid du Colombier break;
28963afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
29063afb9a5SDavid du Colombier if(!forwardagent)
29163afb9a5SDavid du Colombier error("server tried to use agent forwarding");
29263afb9a5SDavid du Colombier handleagentoclose(m);
29363afb9a5SDavid du Colombier break;
29463afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_DATA:
29563afb9a5SDavid du Colombier if(!forwardagent)
29663afb9a5SDavid du Colombier error("server tried to use agent forwarding");
29763afb9a5SDavid du Colombier handleagentmsg(m);
29863afb9a5SDavid du Colombier break;
29963afb9a5SDavid du Colombier
30063afb9a5SDavid du Colombier case SSH_SMSG_STDOUT_DATA:
30163afb9a5SDavid du Colombier fd = outfd;
30263afb9a5SDavid du Colombier goto Dataout;
30363afb9a5SDavid du Colombier case SSH_SMSG_STDERR_DATA:
30463afb9a5SDavid du Colombier fd = 2;
30563afb9a5SDavid du Colombier goto Dataout;
30663afb9a5SDavid du Colombier Dataout:
30763afb9a5SDavid du Colombier len = getlong(m);
30863afb9a5SDavid du Colombier s = (char*)getbytes(m, len);
30963afb9a5SDavid du Colombier if(crstrip){
31063afb9a5SDavid du Colombier es = s+len;
31163afb9a5SDavid du Colombier for(r=w=s; r<es; r++)
31263afb9a5SDavid du Colombier if(*r != '\r')
31363afb9a5SDavid du Colombier *w++ = *r;
31463afb9a5SDavid du Colombier len = w-s;
31563afb9a5SDavid du Colombier }
31663afb9a5SDavid du Colombier write(fd, s, len);
31763afb9a5SDavid du Colombier break;
31863afb9a5SDavid du Colombier }
31963afb9a5SDavid du Colombier free(m);
32063afb9a5SDavid du Colombier }
32163afb9a5SDavid du Colombier }
32263afb9a5SDavid du Colombier
32363afb9a5SDavid du Colombier /*
32463afb9a5SDavid du Colombier * turn keyboard raw mode on
32563afb9a5SDavid du Colombier */
32663afb9a5SDavid du Colombier static void
rawon(void)32763afb9a5SDavid du Colombier rawon(void)
32863afb9a5SDavid du Colombier {
32963afb9a5SDavid du Colombier if(raw)
33063afb9a5SDavid du Colombier return;
33163afb9a5SDavid du Colombier if(cooked)
33263afb9a5SDavid du Colombier return;
33363afb9a5SDavid du Colombier if(consctl < 0)
33463afb9a5SDavid du Colombier consctl = open("/dev/consctl", OWRITE);
33563afb9a5SDavid du Colombier if(consctl < 0)
33663afb9a5SDavid du Colombier return;
33763afb9a5SDavid du Colombier if(write(consctl, "rawon", 5) != 5)
33863afb9a5SDavid du Colombier return;
33963afb9a5SDavid du Colombier raw = 1;
34063afb9a5SDavid du Colombier }
34163afb9a5SDavid du Colombier
34263afb9a5SDavid du Colombier /*
34363afb9a5SDavid du Colombier * turn keyboard raw mode off
34463afb9a5SDavid du Colombier */
34563afb9a5SDavid du Colombier static void
rawoff(void)34663afb9a5SDavid du Colombier rawoff(void)
34763afb9a5SDavid du Colombier {
34863afb9a5SDavid du Colombier if(raw == 0)
34963afb9a5SDavid du Colombier return;
35063afb9a5SDavid du Colombier if(consctl < 0)
35163afb9a5SDavid du Colombier return;
35263afb9a5SDavid du Colombier if(write(consctl, "rawoff", 6) != 6)
35363afb9a5SDavid du Colombier return;
35463afb9a5SDavid du Colombier close(consctl);
35563afb9a5SDavid du Colombier consctl = -1;
35663afb9a5SDavid du Colombier raw = 0;
35763afb9a5SDavid du Colombier }
35863afb9a5SDavid du Colombier
35963afb9a5SDavid du Colombier /*
36063afb9a5SDavid du Colombier * control menu
36163afb9a5SDavid du Colombier */
36263afb9a5SDavid du Colombier #define STDHELP "\t(q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
36363afb9a5SDavid du Colombier
36463afb9a5SDavid du Colombier static int
menu(Conn * c)36563afb9a5SDavid du Colombier menu(Conn *c)
36663afb9a5SDavid du Colombier {
36763afb9a5SDavid du Colombier char buf[1024];
36863afb9a5SDavid du Colombier long n;
36963afb9a5SDavid du Colombier int done;
37063afb9a5SDavid du Colombier int wasraw;
37163afb9a5SDavid du Colombier
37263afb9a5SDavid du Colombier wasraw = raw;
37363afb9a5SDavid du Colombier if(wasraw)
37463afb9a5SDavid du Colombier rawoff();
37563afb9a5SDavid du Colombier
37663afb9a5SDavid du Colombier buf[0] = '?';
37763afb9a5SDavid du Colombier fprint(2, ">>> ");
37863afb9a5SDavid du Colombier for(done = 0; !done; ){
37963afb9a5SDavid du Colombier n = read(0, buf, sizeof(buf)-1);
38063afb9a5SDavid du Colombier if(n <= 0)
38163afb9a5SDavid du Colombier return -1;
38263afb9a5SDavid du Colombier buf[n] = 0;
38363afb9a5SDavid du Colombier switch(buf[0]){
38463afb9a5SDavid du Colombier case '!':
38563afb9a5SDavid du Colombier print(buf);
38663afb9a5SDavid du Colombier system(c, buf+1);
38763afb9a5SDavid du Colombier print("!\n");
38863afb9a5SDavid du Colombier done = 1;
38963afb9a5SDavid du Colombier break;
39063afb9a5SDavid du Colombier case 'i':
39163afb9a5SDavid du Colombier buf[0] = 0x1c;
39263afb9a5SDavid du Colombier sendwritemsg(c, buf, 1);
39363afb9a5SDavid du Colombier done = 1;
39463afb9a5SDavid du Colombier break;
39563afb9a5SDavid du Colombier case '.':
39663afb9a5SDavid du Colombier case 'q':
39763afb9a5SDavid du Colombier done = 1;
39863afb9a5SDavid du Colombier break;
39963afb9a5SDavid du Colombier case 'r':
40063afb9a5SDavid du Colombier crstrip = 1-crstrip;
40163afb9a5SDavid du Colombier done = 1;
40263afb9a5SDavid du Colombier break;
40363afb9a5SDavid du Colombier default:
40463afb9a5SDavid du Colombier fprint(2, STDHELP);
40563afb9a5SDavid du Colombier break;
40663afb9a5SDavid du Colombier }
40763afb9a5SDavid du Colombier if(!done)
40863afb9a5SDavid du Colombier fprint(2, ">>> ");
40963afb9a5SDavid du Colombier }
41063afb9a5SDavid du Colombier
41163afb9a5SDavid du Colombier if(wasraw)
41263afb9a5SDavid du Colombier rawon();
41363afb9a5SDavid du Colombier else
41463afb9a5SDavid du Colombier rawoff();
41563afb9a5SDavid du Colombier return buf[0];
41663afb9a5SDavid du Colombier }
41763afb9a5SDavid du Colombier
41863afb9a5SDavid du Colombier static void
sendwritemsg(Conn * c,char * buf,int n)41963afb9a5SDavid du Colombier sendwritemsg(Conn *c, char *buf, int n)
42063afb9a5SDavid du Colombier {
42163afb9a5SDavid du Colombier Msg *m;
42263afb9a5SDavid du Colombier
42363afb9a5SDavid du Colombier if(n==0)
42463afb9a5SDavid du Colombier m = allocmsg(c, SSH_CMSG_EOF, 0);
42563afb9a5SDavid du Colombier else{
42663afb9a5SDavid du Colombier m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n);
42763afb9a5SDavid du Colombier putlong(m, n);
42863afb9a5SDavid du Colombier putbytes(m, buf, n);
42963afb9a5SDavid du Colombier }
43063afb9a5SDavid du Colombier sendmsg(m);
43163afb9a5SDavid du Colombier }
43263afb9a5SDavid du Colombier
43363afb9a5SDavid du Colombier /*
43463afb9a5SDavid du Colombier * run a command with the network connection as standard IO
43563afb9a5SDavid du Colombier */
43663afb9a5SDavid du Colombier static void
system(Conn * c,char * cmd)43763afb9a5SDavid du Colombier system(Conn *c, char *cmd)
43863afb9a5SDavid du Colombier {
43963afb9a5SDavid du Colombier int pid;
44063afb9a5SDavid du Colombier int p;
44163afb9a5SDavid du Colombier int pfd[2];
44263afb9a5SDavid du Colombier int n;
44363afb9a5SDavid du Colombier int wasconsctl;
44463afb9a5SDavid du Colombier char buf[4096];
44563afb9a5SDavid du Colombier
44663afb9a5SDavid du Colombier if(pipe(pfd) < 0){
44763afb9a5SDavid du Colombier perror("pipe");
44863afb9a5SDavid du Colombier return;
44963afb9a5SDavid du Colombier }
45063afb9a5SDavid du Colombier outfd = pfd[1];
45163afb9a5SDavid du Colombier
45263afb9a5SDavid du Colombier wasconsctl = consctl;
45363afb9a5SDavid du Colombier close(consctl);
45463afb9a5SDavid du Colombier consctl = -1;
45563afb9a5SDavid du Colombier switch(pid = fork()){
45663afb9a5SDavid du Colombier case -1:
45763afb9a5SDavid du Colombier perror("con");
45863afb9a5SDavid du Colombier return;
45963afb9a5SDavid du Colombier case 0:
46063afb9a5SDavid du Colombier close(pfd[1]);
46163afb9a5SDavid du Colombier dup(pfd[0], 0);
46263afb9a5SDavid du Colombier dup(pfd[0], 1);
46363afb9a5SDavid du Colombier close(c->fd[0]); /* same as c->fd[1] */
46463afb9a5SDavid du Colombier close(pfd[0]);
46563afb9a5SDavid du Colombier if(*cmd)
46663afb9a5SDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil);
46763afb9a5SDavid du Colombier else
46863afb9a5SDavid du Colombier execl("/bin/rc", "rc", nil);
46963afb9a5SDavid du Colombier perror("con");
47063afb9a5SDavid du Colombier exits("exec");
47163afb9a5SDavid du Colombier break;
47263afb9a5SDavid du Colombier default:
47363afb9a5SDavid du Colombier close(pfd[0]);
47463afb9a5SDavid du Colombier while((n = read(pfd[1], buf, sizeof(buf))) > 0)
47563afb9a5SDavid du Colombier sendwritemsg(c, buf, n);
47663afb9a5SDavid du Colombier p = waitpid();
47763afb9a5SDavid du Colombier outfd = 1;
47863afb9a5SDavid du Colombier close(pfd[1]);
47963afb9a5SDavid du Colombier if(p < 0 || p != pid)
48063afb9a5SDavid du Colombier return;
48163afb9a5SDavid du Colombier break;
48263afb9a5SDavid du Colombier }
48363afb9a5SDavid du Colombier if(wasconsctl >= 0){
48463afb9a5SDavid du Colombier consctl = open("/dev/consctl", OWRITE);
48563afb9a5SDavid du Colombier if(consctl < 0)
48663afb9a5SDavid du Colombier error("cannot open consctl");
48763afb9a5SDavid du Colombier }
48863afb9a5SDavid du Colombier }
48963afb9a5SDavid du Colombier
49063afb9a5SDavid du Colombier static void
cookedcatchint(void *,char * msg)49163afb9a5SDavid du Colombier cookedcatchint(void*, char *msg)
49263afb9a5SDavid du Colombier {
49363afb9a5SDavid du Colombier if(strstr(msg, "interrupt"))
49463afb9a5SDavid du Colombier noted(NCONT);
49563afb9a5SDavid du Colombier else if(strstr(msg, "kill"))
49663afb9a5SDavid du Colombier noted(NDFLT);
49763afb9a5SDavid du Colombier else
49863afb9a5SDavid du Colombier noted(NCONT);
49963afb9a5SDavid du Colombier }
50063afb9a5SDavid du Colombier
50163afb9a5SDavid du Colombier static int
wasintr(void)50263afb9a5SDavid du Colombier wasintr(void)
50363afb9a5SDavid du Colombier {
50463afb9a5SDavid du Colombier char err[64];
50563afb9a5SDavid du Colombier
50663afb9a5SDavid du Colombier rerrstr(err, sizeof err);
50763afb9a5SDavid du Colombier return strstr(err, "interrupt") != 0;
50863afb9a5SDavid du Colombier }
50963afb9a5SDavid du Colombier
51063afb9a5SDavid du Colombier void
fromstdin(Conn * c)51163afb9a5SDavid du Colombier fromstdin(Conn *c)
51263afb9a5SDavid du Colombier {
51363afb9a5SDavid du Colombier int n;
51463afb9a5SDavid du Colombier char buf[1024];
51563afb9a5SDavid du Colombier int pid;
51663afb9a5SDavid du Colombier int eofs;
51763afb9a5SDavid du Colombier
51863afb9a5SDavid du Colombier switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
51963afb9a5SDavid du Colombier case -1:
52063afb9a5SDavid du Colombier error("fork: %r");
52163afb9a5SDavid du Colombier case 0:
52263afb9a5SDavid du Colombier break;
52363afb9a5SDavid du Colombier default:
52463afb9a5SDavid du Colombier atexitkill(pid);
52563afb9a5SDavid du Colombier return;
52663afb9a5SDavid du Colombier }
52763afb9a5SDavid du Colombier
52863afb9a5SDavid du Colombier atexit(atexitkiller);
52963afb9a5SDavid du Colombier if(interactive)
53063afb9a5SDavid du Colombier rawon();
53163afb9a5SDavid du Colombier
53263afb9a5SDavid du Colombier notify(cookedcatchint);
53363afb9a5SDavid du Colombier
53463afb9a5SDavid du Colombier eofs = 0;
53563afb9a5SDavid du Colombier for(;;){
53663afb9a5SDavid du Colombier n = read(0, buf, sizeof(buf));
53763afb9a5SDavid du Colombier if(n < 0){
53863afb9a5SDavid du Colombier if(wasintr()){
53963afb9a5SDavid du Colombier if(!raw){
54063afb9a5SDavid du Colombier buf[0] = 0x7f;
54163afb9a5SDavid du Colombier n = 1;
54263afb9a5SDavid du Colombier }else
54363afb9a5SDavid du Colombier continue;
54463afb9a5SDavid du Colombier }else
54563afb9a5SDavid du Colombier break;
54663afb9a5SDavid du Colombier }
54763afb9a5SDavid du Colombier if(n == 0){
54863afb9a5SDavid du Colombier if(!c->interactive || ++eofs > 32)
54963afb9a5SDavid du Colombier break;
55063afb9a5SDavid du Colombier }else
55163afb9a5SDavid du Colombier eofs = 0;
55263afb9a5SDavid du Colombier if(interactive && usemenu && n && memchr(buf, 0x1c, n)) {
55363afb9a5SDavid du Colombier if(menu(c)=='q'){
55463afb9a5SDavid du Colombier sendwritemsg(c, "", 0);
55563afb9a5SDavid du Colombier exits("quit");
55663afb9a5SDavid du Colombier }
55763afb9a5SDavid du Colombier continue;
55863afb9a5SDavid du Colombier }
55963afb9a5SDavid du Colombier if(!raw && n==0){
56063afb9a5SDavid du Colombier buf[0] = 0x4;
56163afb9a5SDavid du Colombier n = 1;
56263afb9a5SDavid du Colombier }
56363afb9a5SDavid du Colombier sendwritemsg(c, buf, n);
56463afb9a5SDavid du Colombier }
56563afb9a5SDavid du Colombier sendwritemsg(c, "", 0);
566*58da3067SDavid du Colombier if(n >= 0) /* weren't hung up upon? */
56763afb9a5SDavid du Colombier atexitdont(atexitkiller);
56863afb9a5SDavid du Colombier exits(nil);
56963afb9a5SDavid du Colombier }
57063afb9a5SDavid du Colombier
57163afb9a5SDavid du Colombier void
winchanges(Conn * c)57263afb9a5SDavid du Colombier winchanges(Conn *c)
57363afb9a5SDavid du Colombier {
57463afb9a5SDavid du Colombier int nrow, ncol, width, height;
57563afb9a5SDavid du Colombier int pid;
57663afb9a5SDavid du Colombier
57763afb9a5SDavid du Colombier switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
57863afb9a5SDavid du Colombier case -1:
57963afb9a5SDavid du Colombier error("fork: %r");
58063afb9a5SDavid du Colombier case 0:
58163afb9a5SDavid du Colombier break;
58263afb9a5SDavid du Colombier default:
58363afb9a5SDavid du Colombier atexitkill(pid);
58463afb9a5SDavid du Colombier return;
58563afb9a5SDavid du Colombier }
58663afb9a5SDavid du Colombier
58763afb9a5SDavid du Colombier for(;;){
58863afb9a5SDavid du Colombier if(readgeom(&nrow, &ncol, &width, &height) < 0)
58963afb9a5SDavid du Colombier break;
59063afb9a5SDavid du Colombier sendwindowsize(c, nrow, ncol, width, height);
59163afb9a5SDavid du Colombier }
59263afb9a5SDavid du Colombier exits(nil);
59363afb9a5SDavid du Colombier }
594