732 lines · 14.0 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 <auth.h>#include <fcall.h>#include <authsrv.h>#include <libsec.h>#include "args.h"#include "drawterm.h" #define Maxfdata 8192#define MaxStr 128 static void	fatal(int, char*, ...);static void	usage(void);static void	writestr(int, char*, char*, int);static int	readstr(int, char*, int);static char	*rexcall(int*, char*, char*);static char *keyspec = "";static AuthInfo *p9any(int); #define system csystemstatic char	*system;static int	cflag;extern int	dbg;extern char*   base;   // fs base for devroot  static char	*srvname = "ncpu";static char	*ealgs = "rc4_256 sha1"; /* message size for exportfs; may be larger so we can do big graphics in CPU window */static int	msgsize = Maxfdata+IOHDRSZ; /* authentication mechanisms */static int	netkeyauth(int);static int	netkeysrvauth(int, char*);static int	p9auth(int);static int	srvp9auth(int, char*); char *authserver; 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,},//	{ "none",	noauth,		srvnoauth,},	{ 0 }};AuthMethod *am = authmethod;	/* default is p9 */ char *p9authproto = "p9any"; int setam(char*); voidexits(char *s){	print("\ngoodbye\n");	for(;;) osyield();} voidusage(void){	fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");	exits("usage");}int fdd; intmountfactotum(void){	int fd;		if((fd = dialfactotum()) < 0)		return -1;	if(sysmount(fd, -1, "/mnt/factotum", MREPL, "") < 0){		fprint(2, "mount factotum: %r\n");		return -1;	}	if((fd = open("/mnt/factotum/ctl", OREAD)) < 0){		fprint(2, "open /mnt/factotum/ctl: %r\n");		return -1;	}	close(fd);	return 0;} voidcpumain(int argc, char **argv){	char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *err, *secstoreserver, *p, *s;	int fd, ms, data; 	/* see if we should use a larger message size */	fd = open("/dev/draw", OREAD);	if(fd > 0){		ms = iounit(fd);		if(msgsize < ms+IOHDRSZ)			msgsize = ms+IOHDRSZ;		close(fd);	} 	user = getenv("USER");	secstoreserver = nil;	authserver = getenv("auth");	if(authserver == nil)		authserver = "auth";	system = getenv("cpu");	if(system == nil)		system = "cpu";	ARGBEGIN{	case 'a':		authserver = EARGF(usage());		break;	case 'c':		system = EARGF(usage());		break;	case 'd':		dbg++;		break;	case 'e':		ealgs = EARGF(usage());		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)			ealgs = nil;		break;	case 'C':		cflag++;		cmd[0] = '!';		cmd[1] = '\0';		while((p = ARGF()) != nil) {			strcat(cmd, " ");			strcat(cmd, p);		}		break;	case 'k':		keyspec = EARGF(usage());		break;	case 'r':		base = EARGF(usage());		break;	case 's':		secstoreserver = EARGF(usage());		break;	case 'u':		user = EARGF(usage());		break;	default:		usage();	}ARGEND; 	if(argc != 0)		usage(); 	if(user == nil)		user = readcons("user", nil, 0); 	if(mountfactotum() < 0){		if(secstoreserver == nil)			secstoreserver = authserver;	 	if(havesecstore(secstoreserver, user)){			s = secstorefetch(secstoreserver, user, nil);			if(s){				if(strlen(s) >= sizeof secstorebuf)					sysfatal("secstore data too big");				strcpy(secstorebuf, s);			}		}	} 	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(getcwd(dat, sizeof(dat)) == 0)		writestr(data, "NO", "dir", 0);	else		writestr(data, dat, "dir", 0); 	/* 	 *  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: %r");	if(strncmp("FS", buf, 2) != 0) {		print("remote cpu: %s", buf);		exits(buf);	} 	if(readstr(data, buf, sizeof buf) < 0)		fatal(1, "waiting for remote export: %r");	if(strcmp(buf, "/") != 0){		print("remote cpu: %s" , buf);		exits(buf);	}	write(data, "OK", 2); 	/* Begin serving the gnot namespace */	exportfs(data, msgsize);	fatal(1, "starting exportfs");} voidfatal(int syserr, char *fmt, ...){	Fmt f;	char *str;	va_list arg; 	fmtstrinit(&f);	fmtprint(&f, "cpu: ");	va_start(arg, fmt);	fmtvprint(&f, fmt, arg);	va_end(arg);	if(syserr)		fmtprint(&f, ": %r");	fmtprint(&f, "\n");	str = fmtstrflush(&f);	write(2, str, strlen(str));	exits(str);} char *negstr = "negotiating authentication method"; char bug[256]; char*rexcall(int *fd, char *host, char *service){	char *na;	char dir[MaxStr];	char err[ERRMAX];	char msg[MaxStr];	int n; 	na = netmkaddr(host, "tcp", "17010");	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, sizeof err);	if(n < 0)		return negstr;	if(*err){		werrstr(err);		return negstr;	} 	/* 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){	int i;	char *p; 	n--;	/* room for \0 */	p = buf;	for(i=0; i<n; i++){		if(read(0, p, 1) != 1)			break;		if(*p == '\n' || *p == '\r')			break;		p++;	}	*p = '\0';	return p-buf;} /* *  user level challenge/response */static intnetkeyauth(int fd){	char chall[32];	char resp[32]; 	strecpy(chall, chall+sizeof 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){	return -1;} 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;	AuthInfo *ai; 	ai = p9any(fd);	if(ai == nil)		return -1;	memmove(key+4, ai->secret, ai->nsecret);	if(ealgs == nil)		return fd; 	/* exchange random numbers */	for(i = 0; i < 4; i++)		key[i] = fastrand();	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); 	/* set up encryption */	i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);	if(i < 0)		werrstr("can't establish ssl connection: %r");	return i;} intauthdial(char *net, char *dom){	int fd;	fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0);	//print("authdial %d\n", fd);	return fd;} static intgetastickets(Ticketreq *tr, char *trbuf, char *tbuf){	int asfd, rv;	char *dom; 	dom = tr->authdom;	asfd = authdial(nil, dom);	if(asfd < 0)		return -1;	rv = _asgetticket(asfd, trbuf, tbuf);	close(asfd);	return rv;} static intmkserverticket(Ticketreq *tr, char *authkey, char *tbuf){	int i;	Ticket t; 	if(strcmp(tr->authid, tr->hostid) != 0)		return -1;	memset(&t, 0, sizeof(t));	memmove(t.chal, tr->chal, CHALLEN);	strcpy(t.cuid, tr->uid);	strcpy(t.suid, tr->uid);	for(i=0; i<DESKEYLEN; i++)		t.key[i] = fastrand();	t.num = AuthTc;	convT2M(&t, tbuf, authkey);	t.num = AuthTs;	convT2M(&t, tbuf+TICKETLEN, authkey);	return 0;} static intgettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf){	if(getastickets(tr, trbuf, tbuf) >= 0)		return 0;	return mkserverticket(tr, key, tbuf);} /* *  prompt user for a key.  don't care about memory leaks, runs standalone */static Attr*promptforkey(char *params){	char *v;	int fd;	Attr *a, *attr;	char *def; 	fd = open("/dev/cons", ORDWR);	if(fd < 0)		sysfatal("opening /dev/cons: %r"); 	attr = _parseattr(params);	fprint(fd, "\n!Adding key:");	for(a=attr; a; a=a->next)		if(a->type != AttrQuery && a->name[0] != '!')			fprint(fd, " %q=%q", a->name, a->val);	fprint(fd, "\n"); 	for(a=attr; a; a=a->next){		v = a->name;		if(a->type != AttrQuery || v[0]=='!')			continue;		def = nil;		if(strcmp(v, "user") == 0)			def = getuser();		a->val = readcons(v, def, 0);		if(a->val == nil)			sysfatal("user terminated key input");		a->type = AttrNameval;	}	for(a=attr; a; a=a->next){		v = a->name;		if(a->type != AttrQuery || v[0]!='!')			continue;		def = nil;		if(strcmp(v+1, "user") == 0)			def = getuser();		a->val = readcons(v+1, def, 1);		if(a->val == nil)

Lines 1–500 of 732.