henesyinit from p9fd787fda5 years agoHistory
554 lines · 8.5 KB · C
RawDownload
#include "ssh.h" int cooked = 0;int crstrip;int interactive = -1;int usemenu = 1;int isatty(int);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 [-CiImpr] [-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;	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 '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':		crstrip = 1;		break;	case 'w':		dowinchange = 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(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); 	if(dowinchange)		winchanges(&c); 	fromstdin(&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, 0);		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); 		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;		}	}}		 /* * Lifted from telnet.c, con.c */ static int raw;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(consctl < 0)		return;	write(consctl, "rawon", 5);	raw = 1;} /* *  turn keyboard raw mode off */static voidrawoff(void){	if(raw == 0)		return;	if(consctl < 0)		return;	write(consctl, "rawoff", 6);	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, 0);		else			execl("/bin/rc", "rc", 0);		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:		rfork(RFNOTEG);		atexitkill(pid);		return;	} 	atexit(atexitkiller);	if(interactive){		if((consctl=open("/dev/consctl", OWRITE)) < 0)			error("Can't turn off echo");		if(cooked==0)			rawon();	}else		consctl = -1; 	if(cooked)		notify(cookedcatchint); 	eofs = 0;	for(;;){		n = read(0, buf, sizeof(buf));		if(n < 0){			if(wasintr()){				if(cooked){

Lines 1–500 of 554.