⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssh.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 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 + -