henesyinit from p9f0ed2a895 years agoHistory
995 lines · 17.2 KB · C
RawDownload
/* * cpu.c - Make a connection to a cpu server * *	   Invoked by listen as 'cpu -R | -N service net netdir' *	    	   by users  as 'cpu [-h system] [-c cmd args ...]' */ #include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <libsec.h> void	remoteside(void);void	fatal(int, char*, ...);void	lclnoteproc(int);void	rmtnoteproc(void);void	catcher(void*, char*);void	usage(void);void	writestr(int, char*, char*, int);int	readstr(int, char*, int);char	*rexcall(int*, char*, char*);int	filter(int);int	setamalg(char*); int 	notechan;char	system[32];int	cflag;int	hflag;int	fflag;int	dbg; char	*srvname = "cpu";char	*exportfs = "/bin/exportfs";char	*ealgs = "rc4_256 sha1"; /* authentication mechanisms */static int	netkeyauth(int);static int	netkeysrvauth(int, char*);static int	p9auth(int);static int	srvp9auth(int, char*); typedef struct AuthMethod AuthMethod;struct AuthMethod {	char	*name;			/* name of method */	int	(*cf)(int);		/* client side authentication */	int	(*sf)(int, char*);	/* server side authentication */} authmethod[] ={	{ "p9",		p9auth,		srvp9auth},	{ "netkey",	netkeyauth,	netkeysrvauth},	{ nil,	nil}};AuthMethod *am = authmethod;	/* default is p9 */ int setam(char*); voidusage(void){	fprint(2, "usage: cpu [-h system] [-a authmethod] [-e 'crypt hash'] [-c cmd args ...]\n");	exits("usage");}int fdd; voidmain(int argc, char **argv){	char dat[128], buf[128], cmd[128], *p, *err;	int data; 	ARGBEGIN{	case 'a':		p = ARGF();		if(p==0)			usage();		if(setam(p) < 0)			fatal(0, "unknown auth method %s\n", p);		break;	case 'e':		ealgs = ARGF();		if(ealgs == nil)			usage();		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)			ealgs = nil;		break;	case 'd':		dbg++;		break;	case 'f':		fflag++;		break;	case 'R':				/* From listen */		remoteside();		break;	case 'h':		hflag++;		p = ARGF();		if(p==0)			usage();		strcpy(system, p);		break;	case 'c':		cflag++;		cmd[0] = '!';		cmd[1] = '\0';		while(p = ARGF()) {			strcat(cmd, " ");			strcat(cmd, p);		}		break;	default:		usage();	}ARGEND; 	if(argv);	if(argc != 0)		usage(); 	if(hflag == 0) {		p = getenv("cpu");		if(p == 0)			fatal(0, "set $cpu");		strcpy(system, p);	} 	if(err = rexcall(&data, system, srvname))		fatal(1, "%s: %s", err, system); 	/* Tell the remote side the command to execute and where our working directory is */	if(cflag)		writestr(data, cmd, "command", 0);	if(getwd(dat, sizeof(dat)) == 0)		writestr(data, "NO", "dir", 0);	else		writestr(data, dat, "dir", 0); 	/* start up a process to pass along notes */	lclnoteproc(data); 	/* 	 *  Wait for the other end to execute and start our file service	 *  of /mnt/term	 */	if(readstr(data, buf, sizeof(buf)) < 0)		fatal(1, "waiting for FS");	if(strncmp("FS", buf, 2) != 0) {		print("remote cpu: %s", buf);		exits(buf);	} 	if(fflag)		data = filter(data); 	/* Begin serving the gnot namespace */	close(0);	dup(data, 0);	close(data);	if(dbg)		execl(exportfs, exportfs, "-d", 0);	else		execl(exportfs, exportfs, 0);	fatal(1, "starting exportfs");} voidfatal(int syserr, char *fmt, ...){	char buf[ERRLEN];	va_list arg; 	va_start(arg, fmt);	doprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	if(syserr)		fprint(2, "cpu: %s: %r\n", buf);	else		fprint(2, "cpu: %s\n", buf);	exits(buf);} char *negstr = "negotiating authentication method"; /* Invoked with stdin, stdout and stderr connected to the network connection */voidremoteside(void){	char user[NAMELEN], home[128], buf[128], xdir[128], cmd[128], err[128];	int i, n, fd, badchdir, gotcmd; 	fd = 0; 	/* negotiate authentication mechanism */	n = readstr(fd, cmd, sizeof(cmd));	if(n < 0)		fatal(1, "authenticating");	if(setamalg(cmd) < 0){		snprint(err, sizeof err, "unsupported auth method '%s'", cmd);		writestr(fd, err, nil, 0);		fatal(1, "bad auth method %s", cmd);	} else		writestr(fd, "", "", 1); 	fd = (*am->sf)(fd, user);	if(fd < 0)		fatal(1, "srvauth");	if(newns(user, 0) < 0)		fatal(1, "newns"); 	/* Set environment values for the user */	putenv("user", user);	sprint(home, "/usr/%s", user);	putenv("home", home); 	/* Now collect invoking cpus current directory or possibly a command */	gotcmd = 0;	if(readstr(fd, xdir, sizeof(xdir)) < 0)		fatal(1, "dir/cmd");	if(xdir[0] == '!') {		strcpy(cmd, &xdir[1]);		gotcmd = 1;		if(readstr(fd, xdir, sizeof(xdir)) < 0)			fatal(1, "dir");	} 	/* Establish the new process at the current working directory of the	 * gnot */	badchdir = 0;	if(strcmp(xdir, "NO") == 0)		chdir(home);	else if(chdir(xdir) < 0) {		badchdir = 1;		chdir(home);	} 	/* Start the gnot serving its namespace */	writestr(fd, "FS", "FS", 0);	writestr(fd, "/", "exportfs dir", 0); 	n = read(fd, buf, sizeof(buf));	if(n != 2 || buf[0] != 'O' || buf[1] != 'K')		exits("remote tree"); 	/* push fcall and note proc */	if(fflag)		fd = filter(fd);	if(amount(fd, "/mnt/term", MCREATE|MREPL, "") < 0)		exits("mount failed");	close(fd); 	/* the remote noteproc uses the mount so it must follow it */	rmtnoteproc(); 	for(i = 0; i < 3; i++)		close(i); 	if(open("/mnt/term/dev/cons", OREAD) != 0){		exits("open stdin");	}	if(open("/mnt/term/dev/cons", OWRITE) != 1){		exits("open stdout");	}	dup(1, 2); 	if(badchdir)		print("cpu: failed to chdir to '%s'\n", xdir); 	if(gotcmd)		execl("/bin/rc", "rc", "-lc", cmd, 0);	else		execl("/bin/rc", "rc", "-li", 0);	fatal(1, "exec shell");} char*rexcall(int *fd, char *host, char *service){	char *na;	char dir[4*NAMELEN];	char err[ERRLEN];	char msg[128];	int n; 	na = netmkaddr(host, 0, service);	if((*fd = dial(na, 0, dir, 0)) < 0)		return "can't dial"; 	/* negotiate authentication mechanism */	if(ealgs != nil)		snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);	else		snprint(msg, sizeof(msg), "%s", am->name);	writestr(*fd, msg, negstr, 0);	n = readstr(*fd, err, ERRLEN);	if(n < 0)		return negstr;	if(*err){		werrstr(err);		return negstr;	} 	if(strstr(dir, "tcp"))		fflag = 1; 	/* authenticate */	*fd = (*am->cf)(*fd);	if(*fd < 0)		return "can't authenticate";	return 0;} voidwritestr(int fd, char *str, char *thing, int ignore){	int l, n; 	l = strlen(str);	n = write(fd, str, l+1);	if(!ignore && n < 0)		fatal(1, "writing network: %s", thing);} intreadstr(int fd, char *str, int len){	int n; 	while(len) {		n = read(fd, str, 1);		if(n < 0) 			return -1;		if(*str == '\0')			return 0;		str++;		len--;	}	return -1;} static intreadln(char *buf, int n){	char *p = buf; 	n--;	while(n > 0){		if(read(0, p, 1) != 1)			break;		if(*p == '\n' || *p == '\r'){			*p = 0;			return p-buf;		}		p++;	}	*p = 0;	return p-buf;} /* *  user level challenge/response */static intnetkeyauth(int fd){	char chall[NAMELEN];	char resp[NAMELEN]; 	strcpy(chall, getuser());	print("user[%s]: ", chall);	if(readln(resp, sizeof(resp)) < 0)		return -1;	if(*resp != 0)		strcpy(chall, resp);	writestr(fd, chall, "challenge/response", 1); 	for(;;){		if(readstr(fd, chall, sizeof chall) < 0)			break;		if(*chall == 0)			return fd;		print("challenge: %s\nresponse: ", chall);		if(readln(resp, sizeof(resp)) < 0)			break;		writestr(fd, resp, "challenge/response", 1);	}	return -1;} static intnetkeysrvauth(int fd, char *user){	char response[NAMELEN];	Chalstate ch;	int tries; 	if(readstr(fd, user, NAMELEN) < 0)		return -1; 	for(tries = 0; tries < 10; tries++){		if(getchal(&ch, user) < 0)			return -1;		writestr(fd, ch.chal, "challenge", 1);		if(readstr(fd, response, sizeof response) < 0)			return -1;		if(chalreply(&ch, response) >= 0)			break;	}	if(tries >= 10)		return -1;	writestr(fd, "", "challenge", 1);	return fd;} static voidmksecret(char *t, uchar *f){	sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",		f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);} /* *  plan9 authentication followed by rc4 encryption */static intp9auth(int fd){	uchar key[16];	uchar digest[SHA1dlen];	char fromclientsecret[21];	char fromserversecret[21];	int i; 	if(authnonce(fd, key+4) < 0)		return -1; 	if(ealgs == nil)		return fd; 	/* exchange random numbers */	srand(truerand());	for(i = 0; i < 4; i++)		key[i] = rand();	if(write(fd, key, 4) != 4)		return -1;	if(readn(fd, key+12, 4) != 4)		return -1; 	/* scramble into two secrets */	sha1(key, sizeof(key), digest, nil);	mksecret(fromclientsecret, digest);	mksecret(fromserversecret, digest+10); 	fflag = 0; 	/* set up encryption */	return pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);} static intsrvp9auth(int fd, char *user){	uchar key[16];	uchar digest[SHA1dlen];	char fromclientsecret[21];	char fromserversecret[21];	int i; 	if(srvauthnonce(fd, user, key+4) < 0)		return -1; 	if(ealgs == nil)		return fd; 	/* exchange random numbers */	srand(truerand());	for(i = 0; i < 4; i++)		key[i+12] = rand();	if(readn(fd, key, 4) != 4)		return -1;	if(write(fd, key+12, 4) != 4)		return -1; 	/* scramble into two secrets */	sha1(key, sizeof(key), digest, nil);	mksecret(fromclientsecret, digest);	mksecret(fromserversecret, digest+10); 	fflag = 0; 	/* set up encryption */	return pushssl(fd, ealgs, fromserversecret, fromclientsecret, nil);} /* Network on fd1, mount driver on fd0 */intfilter(int fd){	int p[2]; 

Lines 1–500 of 995.