1*63afb9a5SDavid du Colombier /* remote login via ssh v1 */ 2*63afb9a5SDavid du Colombier #include "ssh.h" 3*63afb9a5SDavid du Colombier 4*63afb9a5SDavid du Colombier int cooked = 0; /* user wants cooked mode */ 5*63afb9a5SDavid du Colombier int raw = 0; /* console is in raw mode */ 6*63afb9a5SDavid du Colombier int crstrip; 7*63afb9a5SDavid du Colombier int interactive = -1; 8*63afb9a5SDavid du Colombier int usemenu = 1; 9*63afb9a5SDavid du Colombier int isatty(int); 10*63afb9a5SDavid du Colombier int rawhack; 11*63afb9a5SDavid du Colombier int forwardagent = 0; 12*63afb9a5SDavid du Colombier char *buildcmd(int, char**); 13*63afb9a5SDavid du Colombier void fromnet(Conn*); 14*63afb9a5SDavid du Colombier void fromstdin(Conn*); 15*63afb9a5SDavid du Colombier void winchanges(Conn*); 16*63afb9a5SDavid du Colombier static void sendwritemsg(Conn *c, char *buf, int n); 17*63afb9a5SDavid du Colombier 18*63afb9a5SDavid du Colombier /* 19*63afb9a5SDavid du Colombier * Lifted from telnet.c, con.c 20*63afb9a5SDavid du Colombier */ 21*63afb9a5SDavid du Colombier static int consctl = -1; 22*63afb9a5SDavid du Colombier static int outfd = 1; /* changed during system */ 23*63afb9a5SDavid du Colombier static void system(Conn*, char*); 24*63afb9a5SDavid du Colombier 25*63afb9a5SDavid du Colombier Cipher *allcipher[] = { 26*63afb9a5SDavid du Colombier &cipherrc4, 27*63afb9a5SDavid du Colombier &cipherblowfish, 28*63afb9a5SDavid du Colombier &cipher3des, 29*63afb9a5SDavid du Colombier &cipherdes, 30*63afb9a5SDavid du Colombier &ciphernone, 31*63afb9a5SDavid du Colombier &ciphertwiddle, 32*63afb9a5SDavid du Colombier }; 33*63afb9a5SDavid du Colombier 34*63afb9a5SDavid du Colombier Auth *allauth[] = { 35*63afb9a5SDavid du Colombier &authpassword, 36*63afb9a5SDavid du Colombier &authrsa, 37*63afb9a5SDavid du Colombier &authtis, 38*63afb9a5SDavid du Colombier }; 39*63afb9a5SDavid du Colombier 40*63afb9a5SDavid du Colombier char *cipherlist = "blowfish rc4 3des"; 41*63afb9a5SDavid du Colombier char *authlist = "rsa password tis"; 42*63afb9a5SDavid du Colombier 43*63afb9a5SDavid du Colombier Cipher* 44*63afb9a5SDavid du Colombier findcipher(char *name, Cipher **list, int nlist) 45*63afb9a5SDavid du Colombier { 46*63afb9a5SDavid du Colombier int i; 47*63afb9a5SDavid du Colombier 48*63afb9a5SDavid du Colombier for(i=0; i<nlist; i++) 49*63afb9a5SDavid du Colombier if(strcmp(name, list[i]->name) == 0) 50*63afb9a5SDavid du Colombier return list[i]; 51*63afb9a5SDavid du Colombier error("unknown cipher %s", name); 52*63afb9a5SDavid du Colombier return nil; 53*63afb9a5SDavid du Colombier } 54*63afb9a5SDavid du Colombier 55*63afb9a5SDavid du Colombier Auth* 56*63afb9a5SDavid du Colombier findauth(char *name, Auth **list, int nlist) 57*63afb9a5SDavid du Colombier { 58*63afb9a5SDavid du Colombier int i; 59*63afb9a5SDavid du Colombier 60*63afb9a5SDavid du Colombier for(i=0; i<nlist; i++) 61*63afb9a5SDavid du Colombier if(strcmp(name, list[i]->name) == 0) 62*63afb9a5SDavid du Colombier return list[i]; 63*63afb9a5SDavid du Colombier error("unknown auth %s", name); 64*63afb9a5SDavid du Colombier return nil; 65*63afb9a5SDavid du Colombier } 66*63afb9a5SDavid du Colombier 67*63afb9a5SDavid du Colombier void 68*63afb9a5SDavid du Colombier usage(void) 69*63afb9a5SDavid du Colombier { 70*63afb9a5SDavid du Colombier fprint(2, "usage: ssh [-CiImPpRr] [-A authlist] [-c cipherlist] [user@]hostname [cmd [args]]\n"); 71*63afb9a5SDavid du Colombier exits("usage"); 72*63afb9a5SDavid du Colombier } 73*63afb9a5SDavid du Colombier 74*63afb9a5SDavid du Colombier void 75*63afb9a5SDavid du Colombier main(int argc, char **argv) 76*63afb9a5SDavid du Colombier { 77*63afb9a5SDavid du Colombier int i, dowinchange, fd, usepty; 78*63afb9a5SDavid du Colombier char *host, *cmd, *user, *p; 79*63afb9a5SDavid du Colombier char *f[16]; 80*63afb9a5SDavid du Colombier Conn c; 81*63afb9a5SDavid du Colombier Msg *m; 82*63afb9a5SDavid du Colombier 83*63afb9a5SDavid du Colombier fmtinstall('B', mpfmt); 84*63afb9a5SDavid du Colombier fmtinstall('H', encodefmt); 85*63afb9a5SDavid du Colombier atexit(atexitkiller); 86*63afb9a5SDavid du Colombier atexitkill(getpid()); 87*63afb9a5SDavid du Colombier 88*63afb9a5SDavid du Colombier dowinchange = 0; 89*63afb9a5SDavid du Colombier if(getenv("LINES")) 90*63afb9a5SDavid du Colombier dowinchange = 1; 91*63afb9a5SDavid du Colombier usepty = -1; 92*63afb9a5SDavid du Colombier user = nil; 93*63afb9a5SDavid du Colombier ARGBEGIN{ 94*63afb9a5SDavid du Colombier case 'B': /* undocumented, debugging */ 95*63afb9a5SDavid du Colombier doabort = 1; 96*63afb9a5SDavid du Colombier break; 97*63afb9a5SDavid du Colombier case 'D': /* undocumented, debugging */ 98*63afb9a5SDavid du Colombier debuglevel = strtol(EARGF(usage()), nil, 0); 99*63afb9a5SDavid du Colombier break; 100*63afb9a5SDavid du Colombier case 'l': /* deprecated */ 101*63afb9a5SDavid du Colombier case 'u': 102*63afb9a5SDavid du Colombier user = EARGF(usage()); 103*63afb9a5SDavid du Colombier break; 104*63afb9a5SDavid du Colombier case 'a': /* used by Unix scp implementations; we must ignore them. */ 105*63afb9a5SDavid du Colombier case 'x': 106*63afb9a5SDavid du Colombier break; 107*63afb9a5SDavid du Colombier 108*63afb9a5SDavid du Colombier case 'A': 109*63afb9a5SDavid du Colombier authlist = EARGF(usage()); 110*63afb9a5SDavid du Colombier break; 111*63afb9a5SDavid du Colombier case 'C': 112*63afb9a5SDavid du Colombier cooked = 1; 113*63afb9a5SDavid du Colombier break; 114*63afb9a5SDavid du Colombier case 'c': 115*63afb9a5SDavid du Colombier cipherlist = EARGF(usage()); 116*63afb9a5SDavid du Colombier break; 117*63afb9a5SDavid du Colombier case 'f': 118*63afb9a5SDavid du Colombier forwardagent = 1; 119*63afb9a5SDavid du Colombier break; 120*63afb9a5SDavid du Colombier case 'I': 121*63afb9a5SDavid du Colombier interactive = 0; 122*63afb9a5SDavid du Colombier break; 123*63afb9a5SDavid du Colombier case 'i': 124*63afb9a5SDavid du Colombier interactive = 1; 125*63afb9a5SDavid du Colombier break; 126*63afb9a5SDavid du Colombier case 'm': 127*63afb9a5SDavid du Colombier usemenu = 0; 128*63afb9a5SDavid du Colombier break; 129*63afb9a5SDavid du Colombier case 'P': 130*63afb9a5SDavid du Colombier usepty = 0; 131*63afb9a5SDavid du Colombier break; 132*63afb9a5SDavid du Colombier case 'p': 133*63afb9a5SDavid du Colombier usepty = 1; 134*63afb9a5SDavid du Colombier break; 135*63afb9a5SDavid du Colombier case 'R': 136*63afb9a5SDavid du Colombier rawhack = 1; 137*63afb9a5SDavid du Colombier break; 138*63afb9a5SDavid du Colombier case 'r': 139*63afb9a5SDavid du Colombier crstrip = 1; 140*63afb9a5SDavid du Colombier break; 141*63afb9a5SDavid du Colombier default: 142*63afb9a5SDavid du Colombier usage(); 143*63afb9a5SDavid du Colombier }ARGEND 144*63afb9a5SDavid du Colombier 145*63afb9a5SDavid du Colombier if(argc < 1) 146*63afb9a5SDavid du Colombier usage(); 147*63afb9a5SDavid du Colombier 148*63afb9a5SDavid du Colombier host = argv[0]; 149*63afb9a5SDavid du Colombier 150*63afb9a5SDavid du Colombier cmd = nil; 151*63afb9a5SDavid du Colombier if(argc > 1) 152*63afb9a5SDavid du Colombier cmd = buildcmd(argc-1, argv+1); 153*63afb9a5SDavid du Colombier 154*63afb9a5SDavid du Colombier if((p = strchr(host, '@')) != nil){ 155*63afb9a5SDavid du Colombier *p++ = '\0'; 156*63afb9a5SDavid du Colombier user = host; 157*63afb9a5SDavid du Colombier host = p; 158*63afb9a5SDavid du Colombier } 159*63afb9a5SDavid du Colombier if(user == nil) 160*63afb9a5SDavid du Colombier user = getenv("user"); 161*63afb9a5SDavid du Colombier if(user == nil) 162*63afb9a5SDavid du Colombier sysfatal("cannot find user name"); 163*63afb9a5SDavid du Colombier 164*63afb9a5SDavid du Colombier privatefactotum(); 165*63afb9a5SDavid du Colombier if(interactive==-1) 166*63afb9a5SDavid du Colombier interactive = isatty(0); 167*63afb9a5SDavid du Colombier 168*63afb9a5SDavid du Colombier if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0) 169*63afb9a5SDavid du Colombier sysfatal("dialing %s: %r", host); 170*63afb9a5SDavid du Colombier 171*63afb9a5SDavid du Colombier memset(&c, 0, sizeof c); 172*63afb9a5SDavid du Colombier c.interactive = interactive; 173*63afb9a5SDavid du Colombier c.fd[0] = c.fd[1] = fd; 174*63afb9a5SDavid du Colombier c.user = user; 175*63afb9a5SDavid du Colombier c.host = host; 176*63afb9a5SDavid du Colombier setaliases(&c, host); 177*63afb9a5SDavid du Colombier 178*63afb9a5SDavid du Colombier c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", "); 179*63afb9a5SDavid du Colombier c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher); 180*63afb9a5SDavid du Colombier for(i=0; i<c.nokcipher; i++) 181*63afb9a5SDavid du Colombier c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher)); 182*63afb9a5SDavid du Colombier 183*63afb9a5SDavid du Colombier c.nokauth = getfields(authlist, f, nelem(f), 1, ", "); 184*63afb9a5SDavid du Colombier c.okauth = emalloc(sizeof(Auth*)*c.nokauth); 185*63afb9a5SDavid du Colombier for(i=0; i<c.nokauth; i++) 186*63afb9a5SDavid du Colombier c.okauth[i] = findauth(f[i], allauth, nelem(allauth)); 187*63afb9a5SDavid du Colombier 188*63afb9a5SDavid du Colombier sshclienthandshake(&c); 189*63afb9a5SDavid du Colombier 190*63afb9a5SDavid du Colombier if(forwardagent){ 191*63afb9a5SDavid du Colombier if(startagent(&c) < 0) 192*63afb9a5SDavid du Colombier forwardagent = 0; 193*63afb9a5SDavid du Colombier } 194*63afb9a5SDavid du Colombier if(usepty == -1) 195*63afb9a5SDavid du Colombier usepty = cmd==nil; 196*63afb9a5SDavid du Colombier if(usepty) 197*63afb9a5SDavid du Colombier requestpty(&c); 198*63afb9a5SDavid du Colombier if(cmd){ 199*63afb9a5SDavid du Colombier m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd)); 200*63afb9a5SDavid du Colombier putstring(m, cmd); 201*63afb9a5SDavid du Colombier }else 202*63afb9a5SDavid du Colombier m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0); 203*63afb9a5SDavid du Colombier sendmsg(m); 204*63afb9a5SDavid du Colombier 205*63afb9a5SDavid du Colombier fromstdin(&c); 206*63afb9a5SDavid du Colombier rfork(RFNOTEG); /* only fromstdin gets notes */ 207*63afb9a5SDavid du Colombier if(dowinchange) 208*63afb9a5SDavid du Colombier winchanges(&c); 209*63afb9a5SDavid du Colombier fromnet(&c); 210*63afb9a5SDavid du Colombier exits(0); 211*63afb9a5SDavid du Colombier } 212*63afb9a5SDavid du Colombier 213*63afb9a5SDavid du Colombier int 214*63afb9a5SDavid du Colombier isatty(int fd) 215*63afb9a5SDavid du Colombier { 216*63afb9a5SDavid du Colombier char buf[64]; 217*63afb9a5SDavid du Colombier 218*63afb9a5SDavid du Colombier buf[0] = '\0'; 219*63afb9a5SDavid du Colombier fd2path(fd, buf, sizeof buf); 220*63afb9a5SDavid du Colombier if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0) 221*63afb9a5SDavid du Colombier return 1; 222*63afb9a5SDavid du Colombier return 0; 223*63afb9a5SDavid du Colombier } 224*63afb9a5SDavid du Colombier 225*63afb9a5SDavid du Colombier char* 226*63afb9a5SDavid du Colombier buildcmd(int argc, char **argv) 227*63afb9a5SDavid du Colombier { 228*63afb9a5SDavid du Colombier int i, len; 229*63afb9a5SDavid du Colombier char *s, *t; 230*63afb9a5SDavid du Colombier 231*63afb9a5SDavid du Colombier len = argc-1; 232*63afb9a5SDavid du Colombier for(i=0; i<argc; i++) 233*63afb9a5SDavid du Colombier len += strlen(argv[i]); 234*63afb9a5SDavid du Colombier s = emalloc(len+1); 235*63afb9a5SDavid du Colombier t = s; 236*63afb9a5SDavid du Colombier for(i=0; i<argc; i++){ 237*63afb9a5SDavid du Colombier if(i) 238*63afb9a5SDavid du Colombier *t++ = ' '; 239*63afb9a5SDavid du Colombier strcpy(t, argv[i]); 240*63afb9a5SDavid du Colombier t += strlen(t); 241*63afb9a5SDavid du Colombier } 242*63afb9a5SDavid du Colombier return s; 243*63afb9a5SDavid du Colombier } 244*63afb9a5SDavid du Colombier 245*63afb9a5SDavid du Colombier 246*63afb9a5SDavid du Colombier void 247*63afb9a5SDavid du Colombier fromnet(Conn *c) 248*63afb9a5SDavid du Colombier { 249*63afb9a5SDavid du Colombier int fd, len; 250*63afb9a5SDavid du Colombier char *s, *es, *r, *w; 251*63afb9a5SDavid du Colombier ulong ex; 252*63afb9a5SDavid du Colombier char buf[64]; 253*63afb9a5SDavid du Colombier Msg *m; 254*63afb9a5SDavid du Colombier 255*63afb9a5SDavid du Colombier for(;;){ 256*63afb9a5SDavid du Colombier m = recvmsg(c, -1); 257*63afb9a5SDavid du Colombier if(m == nil) 258*63afb9a5SDavid du Colombier break; 259*63afb9a5SDavid du Colombier switch(m->type){ 260*63afb9a5SDavid du Colombier default: 261*63afb9a5SDavid du Colombier badmsg(m, 0); 262*63afb9a5SDavid du Colombier 263*63afb9a5SDavid du Colombier case SSH_SMSG_EXITSTATUS: 264*63afb9a5SDavid du Colombier ex = getlong(m); 265*63afb9a5SDavid du Colombier if(ex==0) 266*63afb9a5SDavid du Colombier exits(0); 267*63afb9a5SDavid du Colombier sprint(buf, "%lud", ex); 268*63afb9a5SDavid du Colombier exits(buf); 269*63afb9a5SDavid du Colombier 270*63afb9a5SDavid du Colombier case SSH_MSG_DISCONNECT: 271*63afb9a5SDavid du Colombier s = getstring(m); 272*63afb9a5SDavid du Colombier error("disconnect: %s", s); 273*63afb9a5SDavid du Colombier 274*63afb9a5SDavid du Colombier /* 275*63afb9a5SDavid du Colombier * If we ever add reverse port forwarding, we'll have to 276*63afb9a5SDavid du Colombier * revisit this. It assumes that the agent connections are 277*63afb9a5SDavid du Colombier * the only ones. 278*63afb9a5SDavid du Colombier */ 279*63afb9a5SDavid du Colombier case SSH_SMSG_AGENT_OPEN: 280*63afb9a5SDavid du Colombier if(!forwardagent) 281*63afb9a5SDavid du Colombier error("server tried to use agent forwarding"); 282*63afb9a5SDavid du Colombier handleagentopen(m); 283*63afb9a5SDavid du Colombier break; 284*63afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_INPUT_EOF: 285*63afb9a5SDavid du Colombier if(!forwardagent) 286*63afb9a5SDavid du Colombier error("server tried to use agent forwarding"); 287*63afb9a5SDavid du Colombier handleagentieof(m); 288*63afb9a5SDavid du Colombier break; 289*63afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_OUTPUT_CLOSED: 290*63afb9a5SDavid du Colombier if(!forwardagent) 291*63afb9a5SDavid du Colombier error("server tried to use agent forwarding"); 292*63afb9a5SDavid du Colombier handleagentoclose(m); 293*63afb9a5SDavid du Colombier break; 294*63afb9a5SDavid du Colombier case SSH_MSG_CHANNEL_DATA: 295*63afb9a5SDavid du Colombier if(!forwardagent) 296*63afb9a5SDavid du Colombier error("server tried to use agent forwarding"); 297*63afb9a5SDavid du Colombier handleagentmsg(m); 298*63afb9a5SDavid du Colombier break; 299*63afb9a5SDavid du Colombier 300*63afb9a5SDavid du Colombier case SSH_SMSG_STDOUT_DATA: 301*63afb9a5SDavid du Colombier fd = outfd; 302*63afb9a5SDavid du Colombier goto Dataout; 303*63afb9a5SDavid du Colombier case SSH_SMSG_STDERR_DATA: 304*63afb9a5SDavid du Colombier fd = 2; 305*63afb9a5SDavid du Colombier goto Dataout; 306*63afb9a5SDavid du Colombier Dataout: 307*63afb9a5SDavid du Colombier len = getlong(m); 308*63afb9a5SDavid du Colombier s = (char*)getbytes(m, len); 309*63afb9a5SDavid du Colombier if(crstrip){ 310*63afb9a5SDavid du Colombier es = s+len; 311*63afb9a5SDavid du Colombier for(r=w=s; r<es; r++) 312*63afb9a5SDavid du Colombier if(*r != '\r') 313*63afb9a5SDavid du Colombier *w++ = *r; 314*63afb9a5SDavid du Colombier len = w-s; 315*63afb9a5SDavid du Colombier } 316*63afb9a5SDavid du Colombier write(fd, s, len); 317*63afb9a5SDavid du Colombier break; 318*63afb9a5SDavid du Colombier } 319*63afb9a5SDavid du Colombier free(m); 320*63afb9a5SDavid du Colombier } 321*63afb9a5SDavid du Colombier } 322*63afb9a5SDavid du Colombier 323*63afb9a5SDavid du Colombier /* 324*63afb9a5SDavid du Colombier * turn keyboard raw mode on 325*63afb9a5SDavid du Colombier */ 326*63afb9a5SDavid du Colombier static void 327*63afb9a5SDavid du Colombier rawon(void) 328*63afb9a5SDavid du Colombier { 329*63afb9a5SDavid du Colombier if(raw) 330*63afb9a5SDavid du Colombier return; 331*63afb9a5SDavid du Colombier if(cooked) 332*63afb9a5SDavid du Colombier return; 333*63afb9a5SDavid du Colombier if(consctl < 0) 334*63afb9a5SDavid du Colombier consctl = open("/dev/consctl", OWRITE); 335*63afb9a5SDavid du Colombier if(consctl < 0) 336*63afb9a5SDavid du Colombier return; 337*63afb9a5SDavid du Colombier if(write(consctl, "rawon", 5) != 5) 338*63afb9a5SDavid du Colombier return; 339*63afb9a5SDavid du Colombier raw = 1; 340*63afb9a5SDavid du Colombier } 341*63afb9a5SDavid du Colombier 342*63afb9a5SDavid du Colombier /* 343*63afb9a5SDavid du Colombier * turn keyboard raw mode off 344*63afb9a5SDavid du Colombier */ 345*63afb9a5SDavid du Colombier static void 346*63afb9a5SDavid du Colombier rawoff(void) 347*63afb9a5SDavid du Colombier { 348*63afb9a5SDavid du Colombier if(raw == 0) 349*63afb9a5SDavid du Colombier return; 350*63afb9a5SDavid du Colombier if(consctl < 0) 351*63afb9a5SDavid du Colombier return; 352*63afb9a5SDavid du Colombier if(write(consctl, "rawoff", 6) != 6) 353*63afb9a5SDavid du Colombier return; 354*63afb9a5SDavid du Colombier close(consctl); 355*63afb9a5SDavid du Colombier consctl = -1; 356*63afb9a5SDavid du Colombier raw = 0; 357*63afb9a5SDavid du Colombier } 358*63afb9a5SDavid du Colombier 359*63afb9a5SDavid du Colombier /* 360*63afb9a5SDavid du Colombier * control menu 361*63afb9a5SDavid du Colombier */ 362*63afb9a5SDavid du Colombier #define STDHELP "\t(q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n" 363*63afb9a5SDavid du Colombier 364*63afb9a5SDavid du Colombier static int 365*63afb9a5SDavid du Colombier menu(Conn *c) 366*63afb9a5SDavid du Colombier { 367*63afb9a5SDavid du Colombier char buf[1024]; 368*63afb9a5SDavid du Colombier long n; 369*63afb9a5SDavid du Colombier int done; 370*63afb9a5SDavid du Colombier int wasraw; 371*63afb9a5SDavid du Colombier 372*63afb9a5SDavid du Colombier wasraw = raw; 373*63afb9a5SDavid du Colombier if(wasraw) 374*63afb9a5SDavid du Colombier rawoff(); 375*63afb9a5SDavid du Colombier 376*63afb9a5SDavid du Colombier buf[0] = '?'; 377*63afb9a5SDavid du Colombier fprint(2, ">>> "); 378*63afb9a5SDavid du Colombier for(done = 0; !done; ){ 379*63afb9a5SDavid du Colombier n = read(0, buf, sizeof(buf)-1); 380*63afb9a5SDavid du Colombier if(n <= 0) 381*63afb9a5SDavid du Colombier return -1; 382*63afb9a5SDavid du Colombier buf[n] = 0; 383*63afb9a5SDavid du Colombier switch(buf[0]){ 384*63afb9a5SDavid du Colombier case '!': 385*63afb9a5SDavid du Colombier print(buf); 386*63afb9a5SDavid du Colombier system(c, buf+1); 387*63afb9a5SDavid du Colombier print("!\n"); 388*63afb9a5SDavid du Colombier done = 1; 389*63afb9a5SDavid du Colombier break; 390*63afb9a5SDavid du Colombier case 'i': 391*63afb9a5SDavid du Colombier buf[0] = 0x1c; 392*63afb9a5SDavid du Colombier sendwritemsg(c, buf, 1); 393*63afb9a5SDavid du Colombier done = 1; 394*63afb9a5SDavid du Colombier break; 395*63afb9a5SDavid du Colombier case '.': 396*63afb9a5SDavid du Colombier case 'q': 397*63afb9a5SDavid du Colombier done = 1; 398*63afb9a5SDavid du Colombier break; 399*63afb9a5SDavid du Colombier case 'r': 400*63afb9a5SDavid du Colombier crstrip = 1-crstrip; 401*63afb9a5SDavid du Colombier done = 1; 402*63afb9a5SDavid du Colombier break; 403*63afb9a5SDavid du Colombier default: 404*63afb9a5SDavid du Colombier fprint(2, STDHELP); 405*63afb9a5SDavid du Colombier break; 406*63afb9a5SDavid du Colombier } 407*63afb9a5SDavid du Colombier if(!done) 408*63afb9a5SDavid du Colombier fprint(2, ">>> "); 409*63afb9a5SDavid du Colombier } 410*63afb9a5SDavid du Colombier 411*63afb9a5SDavid du Colombier if(wasraw) 412*63afb9a5SDavid du Colombier rawon(); 413*63afb9a5SDavid du Colombier else 414*63afb9a5SDavid du Colombier rawoff(); 415*63afb9a5SDavid du Colombier return buf[0]; 416*63afb9a5SDavid du Colombier } 417*63afb9a5SDavid du Colombier 418*63afb9a5SDavid du Colombier static void 419*63afb9a5SDavid du Colombier sendwritemsg(Conn *c, char *buf, int n) 420*63afb9a5SDavid du Colombier { 421*63afb9a5SDavid du Colombier Msg *m; 422*63afb9a5SDavid du Colombier 423*63afb9a5SDavid du Colombier if(n==0) 424*63afb9a5SDavid du Colombier m = allocmsg(c, SSH_CMSG_EOF, 0); 425*63afb9a5SDavid du Colombier else{ 426*63afb9a5SDavid du Colombier m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n); 427*63afb9a5SDavid du Colombier putlong(m, n); 428*63afb9a5SDavid du Colombier putbytes(m, buf, n); 429*63afb9a5SDavid du Colombier } 430*63afb9a5SDavid du Colombier sendmsg(m); 431*63afb9a5SDavid du Colombier } 432*63afb9a5SDavid du Colombier 433*63afb9a5SDavid du Colombier /* 434*63afb9a5SDavid du Colombier * run a command with the network connection as standard IO 435*63afb9a5SDavid du Colombier */ 436*63afb9a5SDavid du Colombier static void 437*63afb9a5SDavid du Colombier system(Conn *c, char *cmd) 438*63afb9a5SDavid du Colombier { 439*63afb9a5SDavid du Colombier int pid; 440*63afb9a5SDavid du Colombier int p; 441*63afb9a5SDavid du Colombier int pfd[2]; 442*63afb9a5SDavid du Colombier int n; 443*63afb9a5SDavid du Colombier int wasconsctl; 444*63afb9a5SDavid du Colombier char buf[4096]; 445*63afb9a5SDavid du Colombier 446*63afb9a5SDavid du Colombier if(pipe(pfd) < 0){ 447*63afb9a5SDavid du Colombier perror("pipe"); 448*63afb9a5SDavid du Colombier return; 449*63afb9a5SDavid du Colombier } 450*63afb9a5SDavid du Colombier outfd = pfd[1]; 451*63afb9a5SDavid du Colombier 452*63afb9a5SDavid du Colombier wasconsctl = consctl; 453*63afb9a5SDavid du Colombier close(consctl); 454*63afb9a5SDavid du Colombier consctl = -1; 455*63afb9a5SDavid du Colombier switch(pid = fork()){ 456*63afb9a5SDavid du Colombier case -1: 457*63afb9a5SDavid du Colombier perror("con"); 458*63afb9a5SDavid du Colombier return; 459*63afb9a5SDavid du Colombier case 0: 460*63afb9a5SDavid du Colombier close(pfd[1]); 461*63afb9a5SDavid du Colombier dup(pfd[0], 0); 462*63afb9a5SDavid du Colombier dup(pfd[0], 1); 463*63afb9a5SDavid du Colombier close(c->fd[0]); /* same as c->fd[1] */ 464*63afb9a5SDavid du Colombier close(pfd[0]); 465*63afb9a5SDavid du Colombier if(*cmd) 466*63afb9a5SDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil); 467*63afb9a5SDavid du Colombier else 468*63afb9a5SDavid du Colombier execl("/bin/rc", "rc", nil); 469*63afb9a5SDavid du Colombier perror("con"); 470*63afb9a5SDavid du Colombier exits("exec"); 471*63afb9a5SDavid du Colombier break; 472*63afb9a5SDavid du Colombier default: 473*63afb9a5SDavid du Colombier close(pfd[0]); 474*63afb9a5SDavid du Colombier while((n = read(pfd[1], buf, sizeof(buf))) > 0) 475*63afb9a5SDavid du Colombier sendwritemsg(c, buf, n); 476*63afb9a5SDavid du Colombier p = waitpid(); 477*63afb9a5SDavid du Colombier outfd = 1; 478*63afb9a5SDavid du Colombier close(pfd[1]); 479*63afb9a5SDavid du Colombier if(p < 0 || p != pid) 480*63afb9a5SDavid du Colombier return; 481*63afb9a5SDavid du Colombier break; 482*63afb9a5SDavid du Colombier } 483*63afb9a5SDavid du Colombier if(wasconsctl >= 0){ 484*63afb9a5SDavid du Colombier consctl = open("/dev/consctl", OWRITE); 485*63afb9a5SDavid du Colombier if(consctl < 0) 486*63afb9a5SDavid du Colombier error("cannot open consctl"); 487*63afb9a5SDavid du Colombier } 488*63afb9a5SDavid du Colombier } 489*63afb9a5SDavid du Colombier 490*63afb9a5SDavid du Colombier static void 491*63afb9a5SDavid du Colombier cookedcatchint(void*, char *msg) 492*63afb9a5SDavid du Colombier { 493*63afb9a5SDavid du Colombier if(strstr(msg, "interrupt")) 494*63afb9a5SDavid du Colombier noted(NCONT); 495*63afb9a5SDavid du Colombier else if(strstr(msg, "kill")) 496*63afb9a5SDavid du Colombier noted(NDFLT); 497*63afb9a5SDavid du Colombier else 498*63afb9a5SDavid du Colombier noted(NCONT); 499*63afb9a5SDavid du Colombier } 500*63afb9a5SDavid du Colombier 501*63afb9a5SDavid du Colombier static int 502*63afb9a5SDavid du Colombier wasintr(void) 503*63afb9a5SDavid du Colombier { 504*63afb9a5SDavid du Colombier char err[64]; 505*63afb9a5SDavid du Colombier 506*63afb9a5SDavid du Colombier rerrstr(err, sizeof err); 507*63afb9a5SDavid du Colombier return strstr(err, "interrupt") != 0; 508*63afb9a5SDavid du Colombier } 509*63afb9a5SDavid du Colombier 510*63afb9a5SDavid du Colombier void 511*63afb9a5SDavid du Colombier fromstdin(Conn *c) 512*63afb9a5SDavid du Colombier { 513*63afb9a5SDavid du Colombier int n; 514*63afb9a5SDavid du Colombier char buf[1024]; 515*63afb9a5SDavid du Colombier int pid; 516*63afb9a5SDavid du Colombier int eofs; 517*63afb9a5SDavid du Colombier 518*63afb9a5SDavid du Colombier switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){ 519*63afb9a5SDavid du Colombier case -1: 520*63afb9a5SDavid du Colombier error("fork: %r"); 521*63afb9a5SDavid du Colombier case 0: 522*63afb9a5SDavid du Colombier break; 523*63afb9a5SDavid du Colombier default: 524*63afb9a5SDavid du Colombier atexitkill(pid); 525*63afb9a5SDavid du Colombier return; 526*63afb9a5SDavid du Colombier } 527*63afb9a5SDavid du Colombier 528*63afb9a5SDavid du Colombier atexit(atexitkiller); 529*63afb9a5SDavid du Colombier if(interactive) 530*63afb9a5SDavid du Colombier rawon(); 531*63afb9a5SDavid du Colombier 532*63afb9a5SDavid du Colombier notify(cookedcatchint); 533*63afb9a5SDavid du Colombier 534*63afb9a5SDavid du Colombier eofs = 0; 535*63afb9a5SDavid du Colombier for(;;){ 536*63afb9a5SDavid du Colombier n = read(0, buf, sizeof(buf)); 537*63afb9a5SDavid du Colombier if(n < 0){ 538*63afb9a5SDavid du Colombier if(wasintr()){ 539*63afb9a5SDavid du Colombier if(!raw){ 540*63afb9a5SDavid du Colombier buf[0] = 0x7f; 541*63afb9a5SDavid du Colombier n = 1; 542*63afb9a5SDavid du Colombier }else 543*63afb9a5SDavid du Colombier continue; 544*63afb9a5SDavid du Colombier }else 545*63afb9a5SDavid du Colombier break; 546*63afb9a5SDavid du Colombier } 547*63afb9a5SDavid du Colombier if(n == 0){ 548*63afb9a5SDavid du Colombier if(!c->interactive || ++eofs > 32) 549*63afb9a5SDavid du Colombier break; 550*63afb9a5SDavid du Colombier }else 551*63afb9a5SDavid du Colombier eofs = 0; 552*63afb9a5SDavid du Colombier if(interactive && usemenu && n && memchr(buf, 0x1c, n)) { 553*63afb9a5SDavid du Colombier if(menu(c)=='q'){ 554*63afb9a5SDavid du Colombier sendwritemsg(c, "", 0); 555*63afb9a5SDavid du Colombier exits("quit"); 556*63afb9a5SDavid du Colombier } 557*63afb9a5SDavid du Colombier continue; 558*63afb9a5SDavid du Colombier } 559*63afb9a5SDavid du Colombier if(!raw && n==0){ 560*63afb9a5SDavid du Colombier buf[0] = 0x4; 561*63afb9a5SDavid du Colombier n = 1; 562*63afb9a5SDavid du Colombier } 563*63afb9a5SDavid du Colombier sendwritemsg(c, buf, n); 564*63afb9a5SDavid du Colombier } 565*63afb9a5SDavid du Colombier sendwritemsg(c, "", 0); 566*63afb9a5SDavid du Colombier atexitdont(atexitkiller); 567*63afb9a5SDavid du Colombier exits(nil); 568*63afb9a5SDavid du Colombier } 569*63afb9a5SDavid du Colombier 570*63afb9a5SDavid du Colombier void 571*63afb9a5SDavid du Colombier winchanges(Conn *c) 572*63afb9a5SDavid du Colombier { 573*63afb9a5SDavid du Colombier int nrow, ncol, width, height; 574*63afb9a5SDavid du Colombier int pid; 575*63afb9a5SDavid du Colombier 576*63afb9a5SDavid du Colombier switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){ 577*63afb9a5SDavid du Colombier case -1: 578*63afb9a5SDavid du Colombier error("fork: %r"); 579*63afb9a5SDavid du Colombier case 0: 580*63afb9a5SDavid du Colombier break; 581*63afb9a5SDavid du Colombier default: 582*63afb9a5SDavid du Colombier atexitkill(pid); 583*63afb9a5SDavid du Colombier return; 584*63afb9a5SDavid du Colombier } 585*63afb9a5SDavid du Colombier 586*63afb9a5SDavid du Colombier for(;;){ 587*63afb9a5SDavid du Colombier if(readgeom(&nrow, &ncol, &width, &height) < 0) 588*63afb9a5SDavid du Colombier break; 589*63afb9a5SDavid du Colombier sendwindowsize(c, nrow, ncol, width, height); 590*63afb9a5SDavid du Colombier } 591*63afb9a5SDavid du Colombier exits(nil); 592*63afb9a5SDavid du Colombier } 593