~kris/9p

9hist

fda9719950183738a9f02077c1d1e22da878a849 — David du Colombier 33 years ago 11b08c1
Plan 9 from Bell Labs 1993-03-30
M boot/aux.c => boot/aux.c +13 -0
@@ 86,6 86,19 @@ readfile(char *name, char *buf, int len)
	return 0;
}

int
writefile(char *name, char *buf, int len)
{
	int f, n;

	f = open(name, OWRITE);
	if(f < 0)
		return -1;
	n = write(f, buf, len);
	close(f);
	return (n != len) ? -1 : 0;
}

void
setenv(char *name, char *val)
{

M boot/boot.c => boot/boot.c +8 -9
@@ 1,5 1,6 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include "../boot/boot.h"

#define DEFSYS "bootes"


@@ 12,7 13,6 @@ char	cputype[NAMELEN];
char	terminal[NAMELEN];
char	sys[2*NAMELEN];
char	username[NAMELEN];
char	*sauth;
char	bootfile[3*NAMELEN];
char	conffile[NAMELEN];



@@ 21,6 21,7 @@ int fflag;
int kflag;
int aflag;
int pflag;
int afd = -1;

static void	swapproc(void);
static Method	*rootserver(char*);


@@ 94,9 95,9 @@ boot(int argc, char *argv[])
		fatal("can't connect to file server");
	if(!islocal && !ishybrid){
		nop(fd);
		session(fd);
		if(cfs)
			fd = (*cfs)(fd);
		doauthenticate(fd, mp);
	}
	srvcreate("boot", fd);



@@ 105,12 106,8 @@ boot(int argc, char *argv[])
	 */
	if(bind("/", "/", MREPL) < 0)
		fatal("bind");
	sauth = "";
	if(mount(fd, "/", MAFTER|MCREATE, "", sauth) < 0){
		sauth = "any";
		if(mount(fd, "/", MAFTER|MCREATE, "", sauth) < 0)
			fatal("mount");
	}
	if(mount(fd, "/", MAFTER|MCREATE, "") < 0)
		fatal("mount");
	close(fd);
	if(cpuflag == 0)
		newkernel();


@@ 127,14 124,16 @@ boot(int argc, char *argv[])
			fd = (*mp->connect)();
			if(fd < 0)
				break;
			mount(fd, "/n/kfs", MAFTER|MCREATE, "", "") ;
			mount(fd, "/n/kfs", MAFTER|MCREATE, "") ;
			close(fd);
			break;
		}
	}

	settime(islocal);
	close(afd);
	swapproc();
	remove("#e/password");

	sprint(cmd, "/%s/init", cputype);
	sprint(flags, "-%s%s%s", cpuflag ? "c" : "t", mflag ? "m" : "", aflag ? "a" : "");

M boot/boot.h => boot/boot.h +11 -7
@@ 11,21 11,22 @@ struct Method
extern char*	bootdisk;
extern int	(*cfs)(int);
extern int	cpuflag;
extern char	cputype[NAMELEN];
extern char	cputype[];
extern int	fflag;
extern int	kflag;
extern Method	method[];
extern char	password[NAMELEN];
extern void	(*pword)(int, Method*);
extern char	sys[2*NAMELEN];
extern char	terminal[NAMELEN];
extern char	sys[];
extern uchar	hostkey[];
extern char	terminal[];
extern char	username[NAMELEN];
extern char	bootfile[3*NAMELEN];
extern char	conffile[NAMELEN];
extern char	*sauth;
extern char	bootfile[];
extern char	conffile[];
extern int	afd;

/* libc equivalent */
extern int	cache(int);
extern char*	checkkey(Method*, char*, char*);
extern int	dkauth(void);
extern int	dkconnect(void);
extern void	fatal(char*);


@@ 37,6 38,7 @@ extern void	nop(int);
extern int	outin(char*, char*, int);
extern int	plumb(char*, char*, int*, char*);
extern int	readfile(char*, char*, int);
extern int	readn(int, char*, int);
extern int	sendmsg(int, char*);
extern void	session(int);
extern void	setenv(char*, char*);


@@ 44,8 46,10 @@ extern void	settime(int);
extern void	srvcreate(char*, int);
extern void	userpasswd(int, Method*);
extern void	warning(char*);
extern int	writefile(char*, char*, int);
extern void	boot(int, char **);
extern void	bboot(int, char **);
extern void	doauthenticate(int, Method*);

/* methods */
extern void	config9600(Method*);

A boot/doauthenticate.c => boot/doauthenticate.c +114 -0
@@ 0,0 1,114 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <../boot/boot.h>

static char *pbmsg = "AS protocol botch";
static char *ccmsg = "can't connect to AS";

int
readn(int fd, char *buf, int len)
{
	int m, n;

	for(n = 0; n < len; n += m){
		m = read(fd, buf+n, len-n);
		if(m <= 0)
			return -1;
	}
	return n;
}

static char*
fromauth(Method *mp, char *trbuf, char *tbuf)
{
	char t;
	char *msg;
	static char error[ERRLEN];

	if(afd < 0){
		if(mp->auth == 0)
			fatal("no method for accessing auth server");
		afd = (*mp->auth)();
		if(afd < 0)
			return ccmsg;
	}
	if(write(afd, trbuf, TICKREQLEN) < 0 || read(afd, &t, 1) != 1){
		close(afd);
		afd = -1;
		return pbmsg;
	}
	switch(t){
	case AuthOK:
		msg = 0;
		if(readn(afd, tbuf, 2*TICKETLEN) < 0)
			msg = pbmsg;
		break;
	case AuthErr:
		if(readn(afd, error, ERRLEN) < 0)
			msg = pbmsg;
		else {
			error[ERRLEN-1] = 0;
			msg = error;
		}
		break;
	default:
		msg = pbmsg;
		break;
	}
	return msg;
}

void
doauthenticate(int fd, Method *mp)
{
	char *msg;
	char trbuf[TICKREQLEN];
	char tbuf[2*TICKETLEN];

	print("session...");
	if(fsession(fd, trbuf) < 0)
		fatal("session command failed");

	/* no authentication required? */
	memset(tbuf, 0, 2*TICKETLEN);
	if(trbuf[0] == 0)
		return;

	/* try getting to an auth server */
	msg = fromauth(mp, trbuf, tbuf);
	if(msg == 0)
		if(fauth(fd, tbuf) >= 0)
			return;

	/* didn't work, go for the security hole */
	fprint(2, "no authentication server (%s), using your key as server key\n", msg);
}

char*
checkkey(Method *mp, char *name, char *key)
{
	char *msg;
	Ticketreq tr;
	Ticket t;
	char trbuf[TICKREQLEN];
	char tbuf[TICKETLEN];

	memset(&tr, 0, sizeof tr);
	tr.type = AuthTreq;
	strcpy(tr.authid, name);
	strcpy(tr.hostid, name);
	strcpy(tr.uid, name);
	convTR2M(&tr, trbuf);
	msg = fromauth(mp, trbuf, tbuf);
	if(msg)
		return msg;
	if(msg == ccmsg){
		fprint(2, "boot: can't contact auth server, passwd unchecked\n");
		return 0;
	}
	convM2T(tbuf, &t, key);
	if(t.num == AuthTc && strcmp(name, t.cuid)==0)
		return 0;
	return "no match";
}

M boot/dosboot.c => boot/dosboot.c +3 -3
@@ 30,9 30,9 @@ dosboot(void)
	 */
	if(bind("/", "/", MREPL) < 0)
		fatal("bind");
	if(mount(fd, "/", MAFTER|MCREATE, "#f/fd0disk", "") < 0)
		if(mount(fd, "/", MAFTER|MCREATE, "#f/fd1disk", "") < 0)
			if(mount(fd, "/", MAFTER|MCREATE, "#H/hd0dos", "") < 0)
	if(mount(fd, "/", MAFTER|MCREATE, "#f/fd0disk") < 0)
		if(mount(fd, "/", MAFTER|MCREATE, "#f/fd1disk") < 0)
			if(mount(fd, "/", MAFTER|MCREATE, "#H/hd0dos") < 0)
				fatal("mount");
	close(fd);


M boot/key.c => boot/key.c +50 -27
@@ 3,50 3,73 @@
#include <auth.h>
#include <../boot/boot.h>

char *homsg = "can't set user name or key; please reboot";

getsafe(char *field, int len, uchar *sum, char *file, int pass)
{
	char buf[64];

	if(nvcsum(field, len) != *sum){
		if(readfile(file, buf, sizeof(buf)) < 0){
			kflag |= 1;
			return -1;
		}
		memset(field, 0, len);
		if(pass)
			passtokey(field, buf);
		else
			strncpy(field, buf, len-1);
	}
	return 0;
}

void
key(int islocal, Method *mp)
{
	int fd;
	Nvrsafe safe;
	char password[20];
	int prompt, fd;

	USED(islocal);
	USED(mp);

	prompt = kflag;
	fd = open("#r/nvram", ORDWR);
	if(fd < 0){
		prompt = 1;
		warning("can't open nvram");
	if(fd < 0
	|| seek(fd, 1024+900, 0) < 0
	|| read(fd, &safe, sizeof safe) != sizeof safe){
		memset(&safe, 0, sizeof(safe));
		warning("can't read nvram");
	}
	if(seek(fd, 1024+900, 0) < 0
	|| read(fd, &safe, sizeof safe) != sizeof safe)
		warning("can't read nvram key");

getp:
	if(prompt){
	if(getsafe(safe.machkey, DESKEYLEN, &safe.machsum, "#e/password", 1) < 0)
		warning("bad nvram key");
	if(getsafe(safe.authid, NAMELEN, &safe.authidsum, "#e/authid", 0) < 0)
		warning("bad authentication id");
	if(getsafe(safe.authdom, DOMLEN, &safe.authdomsum, "#e/authdom", 0) < 0)
		warning("bad authentication domain");
	if(kflag){
		do
			getpasswd(password, sizeof password);
		while(!passtokey(safe.machkey, password));
	}else if(nvcsum(safe.machkey, DESKEYLEN) != safe.machsum){
		warning("bad nvram key");
		prompt = 1;
		kflag = 1;
		goto getp;
	}
	safe.machsum = nvcsum(safe.machkey, DESKEYLEN);
	if(kflag){
		outin("authid", safe.authid, sizeof(safe.authid));
		outin("authdom", safe.authdom, sizeof(safe.authdom));
		safe.machsum = nvcsum(safe.machkey, DESKEYLEN);
		safe.authidsum = nvcsum(safe.authid, sizeof(safe.authid));
		safe.authdomsum = nvcsum(safe.authdom, sizeof(safe.authdom));
		if(seek(fd, 1024+900, 0) < 0
		|| write(fd, &safe, sizeof safe) != sizeof safe)
			warning("can't write key to nvram");
	}
	close(fd);
	fd = open("#c/key", OWRITE);
	if(fd < 0){
		warning("can't open #c/key");
		return;
	}
	else if(write(fd, safe.machkey, DESKEYLEN) != DESKEYLEN)
		warning("can't set #c/key");
	close(fd);

	/* set host's key */
	if(writefile("#c/key", safe.machkey, DESKEYLEN) < 0)
		fatal("#c/key");

	/* set host's owner (and uid of current process) */
	if(writefile("#c/hostowner", safe.authid, strlen(safe.authid)) < 0)
		fatal("#c/hostowner");

	/* set host's domain */
	if(writefile("#c/hostdomain", safe.authdom, strlen(safe.authdom)) < 0)
		fatal("#c/hostdomain");
}

M boot/nopsession.c => boot/nopsession.c +1 -7
@@ 1,5 1,6 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "../boot/boot.h"



@@ 49,10 50,3 @@ nop(int fd)
	print("nop");
	rpc(fd, Tnop);
}

void
session(int fd)
{
	print("session");
	rpc(fd, Tsession);
}

M boot/settime.c => boot/settime.c +6 -5
@@ 1,5 1,6 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "../boot/boot.h"



@@ 40,11 41,11 @@ settime(int islocal)
		f = open(timeserver, ORDWR);
		if(f < 0)
			return;
		if(mount(f, "/n/boot", MREPL, "", sauth) < 0)
			if(mount(f, "/n/boot", MREPL, "", "any") < 0){
				close(f);
				return;
			}
		if(mount(f, "/n/boot", MREPL, "") < 0){
warning("settime mount");
			close(f);
			return;
		}
		close(f);
		if(stat("/n/boot", dirbuf) < 0)
			fatal("stat");

M boot/userpasswd.c => boot/userpasswd.c +20 -41
@@ 8,65 8,44 @@ char	password[NAMELEN];
extern	char *sauth;
#endif asdf

char *homsg = "can't set user name or key; please reboot";

/*
 *  get/set user name and password.  verify password with auth server.
 */
void
userpasswd(int islocal, Method *mp)
{
	char key[7];
	char buf[8 + NAMELEN];
	int fd, crfd;
	int fd;
	char *msg;
	char hostkey[DESKEYLEN];

	if(*username == 0 || strcmp(username, "none") == 0){
		strcpy(username, "none");
		outin("user", username, sizeof(username));
	}
	crfd = fd = -1;
	fd = -1;
	while(strcmp(username, "none") != 0){
		getpasswd(password, sizeof password);
		passtokey(key, password);
		fd = open("#c/key", OWRITE);
		if(fd < 0)
			fatal("can't open #c/key; please reboot");
		if(write(fd, key, 7) != 7)
			fatal("can't write #c/key; please reboot");
		close(fd);
		crfd = open("#c/crypt", ORDWR);
		if(crfd < 0)
			fatal("can't open crypt file");
		write(crfd, "E", 1);
		passtokey(hostkey, password);
		fd = -1;
		if(islocal)
			break;
		if(mp->auth)
			fd = (*mp->auth)();
		if(fd < 0){
			warning("password not checked!");
			break;
		}
		strncpy(buf+8, username, NAMELEN);
		if(read(fd, buf, 8) != 8
		|| write(crfd, buf, 8) != 8
		|| read(crfd, buf, 8) != 8
		|| write(fd, buf, 8 + NAMELEN) != 8 + NAMELEN){
			warning("password not checked!");
		msg = checkkey(mp, username, hostkey);
		if(msg == 0)
			break;
		}
		if(read(fd, buf, 2) == 2 && buf[0]=='O' && buf[1]=='K')
			break;
		close(fd);
		fprint(2, "?%s\n", msg);
		outin("user", username, sizeof(username));
	}
	close(fd);
	close(crfd);

	/* set user now that we're sure */
	fd = open("#c/user", OWRITE|OTRUNC);
	if(fd >= 0){
		if(write(fd, username, strlen(username)) < 0)
			warning("write user name");
	if(fd > 0)
		close(fd);
	}else
		warning("open #c/user");

	/* set host's key */
	if(writefile("#c/key", hostkey, DESKEYLEN) < 0)
		fatal(homsg);

	/* set host's owner (and uid of current process) */
	if(writefile("#c/hostowner", username, strlen(username)) < 0)
		fatal(homsg);
	close(fd);
}

M pc/main.c => pc/main.c +35 -0
@@ 21,6 21,15 @@ PCArch *knownarch[] =
	&generic,
};

/* where b.com leaves configuration info */
#define BOOTARGS	((char*)(KZERO|1024))
#define	BOOTARGSLEN	1024
#define	MAXCONF		32

char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;

void
main(void)
{


@@ 82,6 91,7 @@ ulong garbage;
void
init0(void)
{
	int i;
	char tstr[32];

	u->nerrlab = 0;


@@ 102,6 112,8 @@ init0(void)
	chandevinit();

	if(!waserror()){
		for(i = 0; i < nconf; i++)
			ksetenv(confname[i], confval[i]);
		strcpy(tstr, arch->id);
		strcat(tstr, " %s");
		ksetterm(tstr);


@@ 229,6 241,8 @@ confinit(void)
	long x, i, j, *l;
	int pcnt;
	ulong ktop;
	char *cp;
	char *line[MAXCONF];

	/*
	 *  the first 640k is the standard useful memory


@@ 284,6 298,27 @@ confinit(void)

	conf.topofmem = i*MB;

	/*
	 *  parse configuration args from dos file p9rc
	 */
	cp = BOOTARGS;	/* where b.com leaves it's config */
	cp[BOOTARGSLEN-1] = 0;
	i = getfields(cp, line, MAXCONF, '\n');
	for(j = 0; j < i; j++){
		cp = strchr(line[j], '\r');
		if(cp)
			*cp = 0;
		cp = strchr(line[j], '=');
		if(cp == 0)
			continue;
		*cp++ = 0;
		if(cp - line[j] >= NAMELEN+1)
			*(line[j]+NAMELEN-1) = 0;
		confname[nconf] = line[j];
		confval[nconf] = cp;
		nconf++;
	}

	conf.monitor = 1;
	conf.nproc = 30 + i*5;
	conf.nswap = conf.nproc*80;

A port/auth.c => port/auth.c +508 -0
@@ 0,0 1,508 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

typedef struct Crypt	Crypt;
struct Crypt
{
	Crypt		*next;
	Ticket		t;
	Authenticator	a;
	char		tbuf[TICKETLEN];	/* remote ticket */
};

typedef struct Session	Session;
struct Session
{
	Lock;
	Crypt	*cache;			/* cache of tickets */
	char	cchal[CHALLEN];		/* client challenge */
	char	schal[CHALLEN];		/* server challenge */
	char	authid[NAMELEN];	/* server encryption uid */
	char	authdom[DOMLEN];	/* server encryption domain */
	ulong	cid;			/* challenge id */
};

struct
{
	Lock;
	Crypt		*free;
} cryptalloc;

char	eve[NAMELEN] = "bootes";
char	evekey[DESKEYLEN];
char	hostdomain[DOMLEN];

/*
 *  return true if current user is eve
 */
int
iseve(void)
{
	return strcmp(eve, u->p->user) == 0;
}

/*
 * crypt entries are allocated from a pool rather than allocated using malloc so
 * the memory can be protected from reading by devproc. The base and top of the
 * crypt arena is stored in palloc for devproc.
 */
Crypt*
newcrypt(void)
{
	Crypt *c;

	lock(&cryptalloc);
	if(cryptalloc.free) {
		c = cryptalloc.free;
		cryptalloc.free = c->next;
		unlock(&cryptalloc);
		memset(c, 0, sizeof(Crypt));
		return c;
	}

	cryptalloc.free = xalloc(sizeof(Crypt)*conf.nproc);
	if(cryptalloc.free == 0)
		panic("newcrypt");

	for(c = cryptalloc.free; c < cryptalloc.free+conf.nproc-1; c++)
		c->next = c+1;

	palloc.cmembase = (ulong)cryptalloc.free;
	palloc.cmemtop = palloc.cmembase+(sizeof(Crypt)*conf.nproc);
	unlock(&cryptalloc);
	return newcrypt();
}

void
freecrypt(Crypt *c)
{
	lock(&cryptalloc);
	c->next = cryptalloc.free;
	cryptalloc.free = c;
	unlock(&cryptalloc);
}

/*
 *  return the info received in the session message on this channel.
 *  if no session message has been exchanged, do it.
 */
long
sysfsession(ulong *arg)
{
	int i, n;
	Chan *c;
	Fcall *f;
	char *buf;
	Crypt *cp;
	Session *s;
	Ticketreq tr;

	validaddr(arg[1], TICKREQLEN, 1);
	f = malloc(sizeof(Fcall));
	if(f == 0)
		error(Enomem);
	buf = malloc(MAXMSG);
	if(buf == 0){
		free(f);
		error(Enomem);
	}
	c = fdtochan(arg[0], OWRITE, 0, 1);
	s = 0;
	if(waserror()) {
		if(s)
			free(s);
		close(c);
		free(buf);
		free(f);
		nexterror();
	}
	s = c->session;
	if(s == 0){
		/*  exchange a session message with the server */
		s = malloc(sizeof(Session));
		if(s == 0)
			error(Enomem);
		memset(s, 0, sizeof(Session));
		for(i = 0; i < CHALLEN; i++)
			s->cchal[i] = nrand(256);
		f->type = Tsession;
		memmove(f->chal, s->cchal, CHALLEN);
		n = convS2M(f, buf);
		if((*devtab[c->type].write)(c, buf, n, 0) != n)
			error(Emountrpc);
		n = (*devtab[c->type].read)(c, buf, MAXMSG, 0);
		if(convM2S(buf, f, n) == 0)
			error(Emountrpc);
		if(f->type == Rsession){
			memmove(s->schal, f->chal, CHALLEN);
			memmove(s->authid, f->authid, NAMELEN);
			memmove(s->authdom, f->authdom, DOMLEN);
		}
		s->cid = 0;
		c->session = s;
	}

	/* 
	 *  If server requires no ticket, or user is "none", or a ticket
	 *  is already cached, zero the request type
	 */
	tr.type = AuthTreq;
	if(strcmp(u->p->user, "none") == 0 || c->session->authid[0] == 0)
		tr.type = 0;
	else for(cp = s->cache; cp; cp = cp->next)
		if(strcmp(cp->t.cuid, u->p->user) == 0){
			tr.type = 0;
			break;
		}

	/*  create ticket request */
	memmove(tr.chal, c->session->schal, CHALLEN);
	memmove(tr.authid, c->session->authid, NAMELEN);
	memmove(tr.authdom, c->session->authdom, DOMLEN);
	memmove(tr.uid, u->p->user, NAMELEN);
	memmove(tr.hostid, eve, NAMELEN);
	convTR2M(&tr, (char*)arg[1]);

	poperror();
	close(c);
	free(buf);
	free(f);
	return 0;
}

/*
 *  attach tickets to a session
 */
long
sysfauth(ulong *arg)
{
	Chan *c;
	char *ta;
	Session *s;
	Crypt *cp, *ncp, **l;
	char tbuf[2*TICKETLEN];

	validaddr(arg[1], 2*TICKETLEN, 0);
	c = fdtochan(arg[0], OWRITE, 0, 1);
	s = c->session;
	if(s == 0)
		error("fauth must follow fsession");
	cp = newcrypt();
	if(waserror()){
		freecrypt(cp);
		nexterror();
	}

	/*  ticket supplied, use it */
	ta = (char*)arg[1];
	memmove(tbuf, ta, 2*TICKETLEN);
	convM2T(tbuf, &cp->t, evekey);
	if(cp->t.num != AuthTc)
		error("bad AuthTc in ticket");
	if(strncmp(u->p->user, cp->t.cuid, NAMELEN) != 0)
		error("bad uid in ticket");
	if(memcmp(cp->t.chal, s->schal, CHALLEN) != 0)
		error("bad chal in ticket");
	memmove(cp->tbuf, tbuf+TICKETLEN, TICKETLEN);

	/* string onto local list, replace old version */
	lock(s);
	l = &s->cache;
	for(ncp = s->cache; ncp; ncp = *l){
		if(strcmp(ncp->t.cuid, u->p->user) == 0){
			*l = ncp->next;
			freecrypt(ncp);
			break;
		}
		l = &ncp->next;
	}
	cp->next = s->cache;
	s->cache = cp;
	unlock(s);
	poperror();
	return 0;
}

/*
 *  free a session created by fsession
 */
void
freesession(Session *s)
{
	Crypt *cp;

	for(cp = s->cache; cp; cp = cp->next)
		freecrypt(cp);
	free(s);
}

/*
 *  called by mattach() to fill in the Tattach message
 */
ulong
authrequest(Session *s, Fcall *f)
{
	Crypt *cp;
	ulong id, dofree;

	/* no authentication if user is "none" or if no ticket required by remote */
	if(s == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0){
		memset(f->ticket, 0, TICKETLEN);
		memset(f->auth, 0, AUTHENTLEN);
		return 0;
	}

	/* look for ticket in cache */
	dofree = 0;
	for(cp = s->cache; cp; cp = cp->next)
		if(strcmp(cp->t.cuid, u->p->user) == 0)
			break;
	if(cp == 0){
		/*
		 *  create a ticket using hostkey, this solves the
		 *  chicken and egg problem
		 */
		cp = newcrypt();
		cp->t.num = AuthTs;
		memmove(cp->t.chal, s->schal, CHALLEN);
		memmove(cp->t.cuid, u->p->user, NAMELEN);
		memmove(cp->t.suid, u->p->user, NAMELEN);
		memmove(cp->t.key, evekey, DESKEYLEN);
		convT2M(&cp->t, f->ticket, evekey);
		dofree = 1;
	} else
		memmove(f->ticket, cp->tbuf, TICKETLEN);
	lock(s);
	id = s->cid++;
	unlock(s);

	/* create an authenticator */
	memmove(cp->a.chal, s->schal, CHALLEN);
	cp->a.num = AuthAc;
	cp->a.id = id;
	convA2M(&cp->a, f->auth, cp->t.key);
	if(dofree)
		freecrypt(cp);
	return id;
}

/*
 *  called by mattach() to check the Rattach message
 */
void
authreply(Session *s, ulong id, Fcall *f)
{
	Crypt *cp;

	if(s == 0)
		return;

	for(cp = s->cache; cp; cp = cp->next)
		if(strcmp(cp->t.cuid, u->p->user) == 0)
			break;

	/* we're getting around authentication */
	if(s == 0 || cp == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0)
		return;

	convM2A(f->rauth, &cp->a, cp->t.key);
	if(cp->a.num != AuthAs){
		print("bad encryption type\n");
		error("server lies");
	}
	if(memcmp(cp->a.chal, s->cchal, sizeof(cp->a.chal))){
		print("bad returned challenge\n");
		error("server lies");
	}	
	if(cp->a.id != id){
		print("bad returned id\n");
		error("server lies");
	}
}

/*
 *  called by devcons() for #c/authenticate
 *
 *  The protocol is
 *	1) read ticket request from #c/authenticate
 *	2) write ticket to #c/authenticate. if it matchs the challenge the
 *	  user is changed to the suid field of the ticket
 *	3) read authenticator (to confirm this is the server advertised)
 */
long
authread(Chan *c, char *a, int n)
{
	Crypt *cp;
	int i;
	Ticketreq tr;

	if(c->aux == 0){
		/*
		 *  first read returns a ticket request
		 */
		if(n != TICKREQLEN)
			error(Ebadarg);
		c->aux = newcrypt();
		cp = c->aux;
		memset(&tr, 0, sizeof(tr));
		tr.type = AuthTreq;
		strcpy(tr.hostid, eve);
		strcpy(tr.authid, eve);
		strcpy(tr.authdom, hostdomain);
		strcpy(tr.uid, u->p->user);
		for(i = 0; i < CHALLEN; i++)
			tr.chal[i] = nrand(256);
		memmove(cp->a.chal, tr.chal, CHALLEN);
		convTR2M(&tr, a);
	} else {
		/*
		 *  subsequent read returns an authenticator
		 */
		if(n != AUTHENTLEN)
			error(Ebadarg);
		cp = c->aux;
		cp->a.num = AuthAs;
		memmove(cp->a.chal, cp->t.chal, CHALLEN);
		cp->a.id = 0;
		convA2M(&cp->a, a, cp->t.key);
		freecrypt(cp);
		c->aux = 0;
	}
	return n;
}

long
authwrite(Chan *c, char *a, int n)
{
	Crypt *cp;

	if(n != TICKETLEN)
		error(Ebadarg);
	if(c->aux == 0)
		error(Ebadarg);
	cp = c->aux;
	convM2T(a, &cp->t, evekey);
	if(cp->t.num != AuthTs || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
		error(Eperm);
	memmove(u->p->user, cp->t.suid, NAMELEN);
	return n;
}

/*
 *  called by devcons() for #c/authcheck
 *
 *  a write of a ticket+authenticator succeeds if they match
 */
long
authcheck(Chan *c, char *a, int n)
{
	Crypt *cp;

	if(n != TICKETLEN+AUTHENTLEN)
		error(Ebadarg);
	if(c->aux == 0)
		c->aux = newcrypt();
	cp = c->aux;
	convM2T(a, &cp->t, evekey);
	if(cp->t.num != AuthTc || strcmp(u->p->user, cp->t.cuid))
		error(Ebadarg);
	convM2A(a+TICKETLEN, &cp->a, cp->t.key);
	if(cp->a.num != AuthAs || memcmp(cp->t.chal, cp->a.chal, CHALLEN))
		error(Eperm);
	return n;
}

void
authclose(Chan *c)
{
	if(c->aux)
		freecrypt(c->aux);
	c->aux = 0;
}

/*
 *  called by devcons() for key device
 */
long
keyread(char *a, int n, long offset)
{
	if(n<DESKEYLEN || offset != 0)
		error(Ebadarg);
	if(!iseve())
		error(Eperm);
	memmove(a, evekey, DESKEYLEN);
	return DESKEYLEN;
}

long
keywrite(char *a, int n)
{
	if(n != DESKEYLEN)
		error(Ebadarg);
	if(!iseve())
		error(Eperm);
	memmove(evekey, a, DESKEYLEN);
	return DESKEYLEN;
}

/*
 *  called by devcons() for user device
 *
 *  anyone can become none
 */
long
userwrite(char *a, int n)
{
	if(n >= NAMELEN)
		error(Ebadarg);
	if(strcmp(a, "none") != 0)
		error(Eperm);
	memset(u->p->user, 0, NAMELEN);
	strcpy(u->p->user, "none");
	return n;
}

/*
 *  called by devcons() for host owner/domain
 *
 *  writing hostowner also sets user
 */
long
hostownerwrite(char *a, int n)
{
	char buf[NAMELEN];

	if(!iseve())
		error(Eperm);
	if(n >= NAMELEN)
		error(Ebadarg);
	memset(buf, 0, NAMELEN);
	strncpy(buf, a, n);
	if(buf[0] == 0)
		error(Ebadarg);
	memmove(eve, buf, NAMELEN);
	memmove(u->p->user, buf, NAMELEN);
	return n;
}

long
hostdomainwrite(char *a, int n)
{
	char buf[DOMLEN];

	if(!iseve())
		error(Eperm);
	if(n >= DOMLEN)
		error(Ebadarg);
	memset(buf, 0, DOMLEN);
	strncpy(buf, a, n);
	if(buf[0] == 0)
		error(Ebadarg);
	memmove(hostdomain, buf, DOMLEN);
	return n;
}

M port/chan.c => port/chan.c +4 -0
@@ 95,6 95,10 @@ void
chanfree(Chan *c)
{
	c->flag = CFREE;
	if(c->session){
		freesession(c->session);
		c->session = 0;
	}
	lock(&chanalloc);
	c->next = chanalloc.free;
	chanalloc.free = c;

M port/dev.c => port/dev.c +6 -7
@@ 126,10 126,8 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
	int i;
	Dir dir;

	for(i=0;; i++) {
	for(i=0;; i++)
		switch((*gen)(c, tab, ntab, i, &dir)){
		case 0:
			break;
		case -1:
			/*
			 *  given a channel, we cannot derive the directory name


@@ 137,15 135,17 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
			 *  by namec.
			 */
			if(c->qid.path & CHDIR){
				devdir(c, c->qid, ".", 0L, eve, CHDIR|0700, &dir);
				devdir(c, c->qid, ".", 0L, eve, CHDIR|0775, &dir);
				convD2M(&dir, db);
				return;
			}
			print("%s %s: devstat %C %lux\n", u->p->text, u->p->user,
						devchar[c->type], c->qid.path);
							devchar[c->type], c->qid.path);
			error(Enonexist);
		case 0:
			break;
		case 1:
			if(eqqid(c->qid, dir.qid)) {
			if(eqqid(c->qid, dir.qid)){
				if(c->flag&CMSG)
					dir.mode |= CHMOUNT;
				convD2M(&dir, db);


@@ 153,7 153,6 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
			}
			break;
		}
	}
}

long

M port/devcons.c => port/devcons.c +48 -105
@@ 21,8 21,6 @@ KIOQ	kbdq;
static Ref	ctl;			/* number of opens to the control file */
static int	raw;			/* true if raw has been requested on a ctl file */

char	eve[NAMELEN] = "bootes";
char	evekey[DESKEYLEN];
char	sysname[NAMELEN];

/*


@@ 184,13 182,8 @@ pprint(char *fmt, ...)
		return 0;

	c = u->p->fgrp->fd[2];
	if(c == 0 || (c->mode!=OWRITE && c->mode!=ORDWR))
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return 0;

	/* Can't afford to take an error in notify */
	if(waserror())
		return 0;

	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;



@@ 199,7 192,7 @@ pprint(char *fmt, ...)
	lock(c);
	c->offset += n;
	unlock(c);
	poperror();

	return n;
}



@@ 325,14 318,16 @@ consactive(void)

enum{
	Qdir,
	Qchal,
	Qauth,
	Qauthcheck,
	Qclock,
	Qcons,
	Qconsctl,
	Qcputime,
	Qcrypt,
	Qhz,
	Qkey,
	Qhostdomain,
	Qhostowner,
	Qklog,
	Qlights,
	Qmsec,


@@ 350,12 345,14 @@ enum{
};

Dirtab consdir[]={
	"chal",		{Qchal},	8,		0666,
	"authenticate",	{Qauth},	0,		0666,
	"authcheck",	{Qauthcheck},	0,		0666,
	"clock",	{Qclock},	2*NUMSIZE,	0444,
	"cons",		{Qcons},	0,		0660,
	"consctl",	{Qconsctl},	0,		0220,
	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
	"crypt",	{Qcrypt},	0,		0666,
	"hostdomain",	{Qhostdomain},	DOMLEN,		0622,
	"hostowner",	{Qhostowner},	NAMELEN,	0622,
	"hz",		{Qhz},		NUMSIZE,	0666,
	"key",		{Qkey},		DESKEYLEN,	0622,
	"klog",		{Qklog},	0,		0444,


@@ 371,7 368,7 @@ Dirtab consdir[]={
	"sysname",	{Qsysname},	0,		0664,
	"sysstat",	{Qsysstat},	0,		0666,
	"time",		{Qtime},	NUMSIZE,	0664,
	"user",		{Quser},	0,		0666,
 	"user",		{Quser},	NAMELEN,	0664,
};

#define	NCONS	(sizeof consdir/sizeof(Dirtab))


@@ 451,14 448,14 @@ consstat(Chan *c, char *dp)
Chan*
consopen(Chan *c, int omode)
{
	c->aux = 0;
	switch(c->qid.path){
	case Qconsctl:
		if(strcmp(u->p->user, eve) != 0)
		if(!iseve())
			error(Eperm);
		incref(&ctl);
		break;
	}
	c->aux = 0;
	return devopen(c, omode, consdir, NCONS, devgen);
}



@@ 473,15 470,18 @@ void
consclose(Chan *c)
{
	/* last close of control file turns off raw */
	if(c->qid.path==Qconsctl && (c->flag&COPEN)){
		lock(&ctl);
		if(--ctl.ref == 0)
			raw = 0;
		unlock(&ctl);
	switch(c->qid.path){
	case Qconsctl:
		if(c->flag&COPEN){
			lock(&ctl);
			if(--ctl.ref == 0)
				raw = 0;
			unlock(&ctl);
		}
	case Qauth:
	case Qauthcheck:
		authclose(c);
	}
	if(c->qid.path == Qcrypt && c->aux)
		free(c->aux);
	c->aux = 0;
}

long


@@ 490,7 490,7 @@ consread(Chan *c, void *buf, long n, ulong offset)
	int ch, i, k, id;
	ulong l;
	char *cbuf = buf;
	char *chal, *b, *bp, *cb;
	char *b, *bp;
	char tmp[128];	/* must be >= 6*NUMSIZE */
	Mach *mp;



@@ 591,34 591,17 @@ consread(Chan *c, void *buf, long n, ulong offset)
		memmove(buf, tmp+k, n);
		return n;

	case Qcrypt:
		cb = c->aux;
		if(!cb)
			return 0;
		if(n > MAXCRYPT)
			n = MAXCRYPT;
		memmove(buf, &cb[1], n);
		return n;
	case Qkey:
		return keyread(buf, n, offset);

	case Qchal:
		if(offset!=0 || n!=8)
			error(Ebadarg);
		chal = u->p->pgrp->crypt->chal;
		chal[0] = RXschal;
		for(i=1; i<AUTHLEN; i++)
			chal[i] = nrand(256);
		memmove(buf, chal, 8);
		encrypt(evekey, buf, 8);
		chal[0] = RXstick;
		return n;
	case Qauth:
		return authread(c, cbuf, n);

	case Qkey:
		if(offset!=0 || n!=DESKEYLEN)
			error(Ebadarg);
		if(strcmp(u->p->user, eve)!=0 || !cpuserver)
			error(Eperm);
		memmove(buf, evekey, DESKEYLEN);
		return n;
	case Qhostowner:
		return readstr(offset, buf, n, eve);

	case Qhostdomain:
		return readstr(offset, buf, n, hostdomain);

	case Quser:
		return readstr(offset, buf, n, u->p->user);


@@ 742,7 725,7 @@ conswrite(Chan *c, void *va, long n, ulong offset)
	char cbuf[64];
	char buf[256];
	long l, bp;
	char *a = va, *cb;
	char *a = va;
	Mach *mp;
	int id, fd, ch;
	Chan *swc;


@@ 801,63 784,23 @@ conswrite(Chan *c, void *va, long n, ulong offset)
		boottime = strtoul(a, 0, 0)-TK2SEC(MACHP(0)->ticks);
		break;

	case Qcrypt:
		cb = c->aux;
		if(!cb){
			/* first byte determines whether encrypting or decrypting */
			cb = c->aux = smalloc(MAXCRYPT+1);
			cb[0] = 'E';
		}
		if(n < 8){
			if(n != 1 || a[0] != 'E' && a[0] != 'D')
				error(Ebadarg);
			cb[0] = a[0];
			return 1;
		}
		if(n > MAXCRYPT)
			n = MAXCRYPT;
		memset(&cb[1], 0, MAXCRYPT);
		memmove(&cb[1], a, n);
		if(cb[0] == 'E')
			encrypt(u->p->pgrp->crypt->key, &cb[1], n);
		else
			decrypt(u->p->pgrp->crypt->key, &cb[1], n);
		break;

	case Qkey:
		if(n != DESKEYLEN)
			error(Ebadarg);
		memmove(u->p->pgrp->crypt->key, a, DESKEYLEN);
		if(strcmp(u->p->user, eve) == 0)
			memmove(evekey, a, DESKEYLEN);
		break;
		return keywrite(a, n);

	case Qhostowner:
		return hostownerwrite(a, n);

	case Qhostdomain:
		return hostdomainwrite(a, n);

	case Quser:
		if(offset!=0 || n>=NAMELEN-1)
			error(Ebadarg);
		strncpy(buf, a, NAMELEN);
		if(strcmp(buf, "none")==0
		|| strcmp(buf, u->p->user)==0
		|| strcmp(u->p->user, eve)==0)
			memmove(u->p->user, buf, NAMELEN);
		else
			error(Eperm);
		if(!cpuserver && strcmp(eve, "bootes")==0)
			memmove(eve, u->p->user, NAMELEN);
		break;
		return userwrite(a, n);

	case Qchal:
		if(offset != 0)
			error(Ebadarg);
		if(n != 8+NAMELEN+DESKEYLEN)
			error(Ebadarg);
		decrypt(evekey, a, n);
		if(memcmp(u->p->pgrp->crypt->chal, a, 8) != 0)
			error(Eperm);
		strncpy(u->p->user, a+8, NAMELEN);
		u->p->user[NAMELEN-1] = '\0';
		memmove(u->p->pgrp->crypt->key, a+8+NAMELEN, DESKEYLEN);
		break;
	case Qauth:
		return authwrite(c, a, n);

	case Qauthcheck:
		return authcheck(c, a, n);

	case Qnull:
		break;

M port/devmnt.c => port/devmnt.c +13 -47
@@ 48,8 48,7 @@ struct Mntalloc
#define MAXRPC		(MAXFDATA+MAXMSG)
#define limit(n, max)	(n > max ? max : n)

Chan*	mattach(Mnt*, char*, char*);
void	mntauth(Mnt *, Mntrpc *, char *, ushort);
Chan*	mattach(Mnt*, char*);
Mnt*	mntchk(Chan*);
void	mntdirfix(uchar*, Chan*);
void	mntdoclunk(Mnt *, Mntrpc *);


@@ 96,7 95,6 @@ mntattach(char *muxattach)
	struct bogus{
		Chan	*chan;
		char	*spec;
		char	*serv;
	}bogus;

	bogus = *((struct bogus *)muxattach);


@@ 110,7 108,7 @@ mntattach(char *muxattach)
				unlock(&mntalloc);
				m->ref++;
				unlock(m);
				return mattach(m, bogus.spec, bogus.serv);
				return mattach(m, bogus.spec);
			}
			unlock(m);	
		}


@@ 157,8 155,14 @@ mntattach(char *muxattach)
		nexterror();
	}

	c = mattach(m, bogus.spec, bogus.serv);
	c = mattach(m, bogus.spec);

	/*
	 *  If exportfs mounts on behalf of a local devmnt, the mount
	 *  point is folded onto the original channel to preserve a single
	 *  fid/tag space.  CHDIR is cleared by exportfs to indicate it
	 *  is supplying the mount.
	 */
	mc = m->c;
	if(mc->type == devno('M', 0) && (c->qid.path&CHDIR) == 0) {
		c->qid.path |= CHDIR;


@@ 174,10 178,11 @@ mntattach(char *muxattach)
}

Chan *
mattach(Mnt *m, char *spec, char *serv)
mattach(Mnt *m, char *spec)
{
	Chan *c;
	Mntrpc *r;
	ulong id;

	r = mntralloc();
	c = devattach('M', spec);


@@ 193,15 198,13 @@ mattach(Mnt *m, char *spec, char *serv)
		nexterror();
	}

	memset(r->request.auth, 0, sizeof r->request.auth);
	if(*serv)
		mntauth(m, r, serv, c->fid);

	r->request.type = Tattach;
	r->request.fid = c->fid;
	memmove(r->request.uname, u->p->user, NAMELEN);
	strncpy(r->request.aname, spec, NAMELEN);
	id = authrequest(m->c->session, &r->request);
	mountrpc(m, r);
	authreply(m->c->session, id, &r->reply);

	c->qid = r->reply.qid;
	c->mchan = m->c;


@@ 211,43 214,6 @@ mattach(Mnt *m, char *spec, char *serv)
	return c;
}

void
mntauth(Mnt *m, Mntrpc *f, char *serv, ushort fid)
{
	int i;
	Mntrpc *r;
	uchar chal[AUTHLEN];

	r = mntralloc();
	if(waserror()) {
		mntfree(r);
		return;
	}

	r->request.type = Tauth;
	r->request.fid = fid;
	memmove(r->request.uname, u->p->user, NAMELEN);
	chal[0] = FScchal;
	for(i = 1; i < AUTHLEN; i++)
		chal[i] = nrand(256);

	memmove(r->request.chal, chal, AUTHLEN);
	strncpy(r->request.chal+AUTHLEN, serv, NAMELEN);
	encrypt(u->p->pgrp->crypt->key, r->request.chal, AUTHLEN+NAMELEN);

	mountrpc(m, r);

	decrypt(u->p->pgrp->crypt->key, r->reply.chal, 2*AUTHLEN+2*DESKEYLEN);
	chal[0] = FSctick;
	poperror();
	if(memcmp(chal, r->reply.chal, AUTHLEN) != 0) {
		mntfree(r);
		error(Eperm);
	}
	memmove(f->request.auth, r->reply.chal+AUTHLEN+DESKEYLEN, AUTHLEN+DESKEYLEN);
	mntfree(r);
}

Chan*
mntclone(Chan *c, Chan *nc)
{

M port/lib.h => port/lib.h +0 -1
@@ 99,7 99,6 @@ typedef struct Waitmsg	Waitmsg;
#define	ERRLEN		64
#define	DIRLEN		116
#define	NAMELEN		28
#define DESKEYLEN	7

struct Qid
{

M port/net.c => port/net.c +1 -28
@@ 136,34 136,7 @@ netwalk(Chan *c, char *name, Network *np)
void
netstat(Chan *c, char *db, Network *np)
{
	int i;
	Dir dir;

	for(i=0;; i++)
		switch(netgen(c, (Dirtab*)np, 0, i, &dir)){
		case -1:
			/*
			 * devices with interesting directories usually don't get
			 * here, which is good because we've lost the name by now.
			 */
			if(c->qid.path & CHDIR){
				devdir(c, c->qid, ".", 0L, eve, CHDIR|0555, &dir);
				convD2M(&dir, db);
				return;
			}
			print("netstat %C %lux\n", devchar[c->type], c->qid.path);
			error(Enonexist);
		case 0:
			break;
		case 1:
			if(eqqid(c->qid, dir.qid)){
				if(c->flag&CMSG)
					dir.mode |= CHMOUNT;
				convD2M(&dir, db);
				return;
			}
			break;
		}
	devstat(c, db, (Dirtab*)np, 1, netgen);
}

Chan *

M port/pgrp.c => port/pgrp.c +0 -49
@@ 8,52 8,6 @@
static Ref pgrpid;
static Ref mountid;

struct
{
	Lock;
	Crypt	*free;
} cryptalloc;

/*
 * crypt entries are allocated from a pool rather than allocated using malloc so
 * the memory can be protected from reading by devproc. The base and top of the
 * crypt arena is stored in palloc for devproc.
 */
Crypt*
newcrypt(void)
{
	Crypt *c;

	lock(&cryptalloc);
	if(cryptalloc.free) {
		c = cryptalloc.free;
		cryptalloc.free = c->next;
		unlock(&cryptalloc);
		return c;
	}

	cryptalloc.free = xalloc(sizeof(Crypt)*conf.nproc);
	if(cryptalloc.free == 0)
		panic("newcrypt");

	for(c = cryptalloc.free; c < cryptalloc.free+conf.nproc-1; c++)
		c->next = c+1;

	palloc.cmembase = (ulong)cryptalloc.free;
	palloc.cmemtop = palloc.cmembase+(sizeof(Crypt)*conf.nproc);
	unlock(&cryptalloc);
	return newcrypt();
}

void
freecrypt(Crypt *c)
{
	lock(&cryptalloc);
	c->next = cryptalloc.free;
	cryptalloc.free = c;
	unlock(&cryptalloc);
}

void
pgrpnote(ulong noteid, char *a, long n, int flag)
{


@@ 92,7 46,6 @@ newpgrp(void)

	p = smalloc(sizeof(Pgrp));
	p->ref = 1;
	p->crypt = newcrypt();
	p->pgrpid = incref(&pgrpid);
	return p;
}


@@ 116,7 69,6 @@ closepgrp(Pgrp *p)
			}
		}
		qunlock(&p->debug);
		freecrypt(p->crypt);
		free(p);
	}
}


@@ 129,7 81,6 @@ pgrpcpy(Pgrp *to, Pgrp *from)

	rlock(&from->ns);

	*to->crypt = *from->crypt;
	e = &from->mnthash[MNTHASH];
	tom = to->mnthash;
	for(h = from->mnthash; h < e; h++) {

M port/portdat.h => port/portdat.h +5 -12
@@ 2,7 2,6 @@ typedef struct Alarms	Alarms;
typedef struct Block	Block;
typedef struct Blist	Blist;
typedef struct Chan	Chan;
typedef struct Crypt	Crypt;
typedef struct Dev	Dev;
typedef struct Dirtab	Dirtab;
typedef struct Egrp	Egrp;


@@ 34,6 33,7 @@ typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct RWlock	RWlock;
typedef struct Sargs	Sargs;
typedef struct Session	Session;
typedef struct Scsi	Scsi;
typedef struct Scsibuf	Scsibuf;
typedef struct Scsidata	Scsidata;


@@ 47,7 47,8 @@ typedef	void   Streamopen(Queue*, Stream*);
typedef	void   Streamclose(Queue*);
typedef	void   Streamreset(void);

#include "fcall.h"
#include <auth.h>
#include <fcall.h>

struct Ref
{


@@ 171,13 172,7 @@ struct Chan
	};
	Chan	*mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
};

struct Crypt
{
	char	key[DESKEYLEN];		/* des encryption key */
	char	chal[8];		/* challenge for setting user name */
	Crypt	*next;
	Session	*session;
};

struct Dev


@@ 453,7 448,6 @@ struct Pgrp
	Ref;				/* also used as a lock when mounting */
	Pgrp	*next;			/* free list */
	ulong	pgrpid;
	Crypt	*crypt;			/* encryption key and challenge */
	QLock	debug;			/* single access via devproc.c */
	RWlock	ns;			/* Namespace many read/one write lock */
	Mhead	*mnthash[MNTHASH];


@@ 746,6 740,7 @@ extern	int	cpuserver;
extern	Rune*	devchar;
extern	Dev	devtab[];
extern  char	eve[];
extern	char	hostdomain[];
extern	uchar	initcode[];
extern	FPsave	initfp;
extern  KIOQ	kbdq;


@@ 783,8 778,6 @@ enum

	RXschal	= 0,
	RXstick	= 1,

	AUTHLEN	= 8,
};

/*

M port/portfns.h => port/portfns.h +13 -0
@@ 2,6 2,12 @@ void		alarmkproc(void*);
Block*		allocb(ulong);
int		anyready(void);
Image*		attachimage(int, Chan*, ulong, ulong);
long		authcheck(Chan*, char*, int);
void		authclose(Chan*);
long		authread(Chan*, char*, int);
ulong		authrequest(Session*, Fcall*);
void		authreply(Session*, ulong, Fcall*);
long		authwrite(Chan*, char*, int);
void		bitdebug(void);
void		bitdepth(void);
void		bitreverse(uchar*, int);


@@ 75,6 81,7 @@ int		freebroken(void);
void		freechan(Chan*);
void		freepte(Segment*, Pte*);
void		freesegs(int);
void		freesession(Session*);
Block*		getb(Blist*);
int		getc(IOQ*);
void		getcolor(ulong, ulong*, ulong*, ulong*);


@@ 84,6 91,8 @@ int		gets(IOQ*, void*, int);
void		gotolabel(Label*);
Block*		grabq(Queue*);
int		haswaitq(void*);
long		hostdomainwrite(char*, int);
long		hostownerwrite(char*, int);
int		hwcursmove(int, int);
int		hwcursset(uchar*, uchar*, int, int);
long		ibrk(ulong, int);


@@ 93,11 102,14 @@ void		initscsi(void);
void		initseg(void);
void		invalidateu(void);
void		isdir(Chan*);
int		iseve(void);
int		ispages(void*);
void		kbdclock(void);
int		kbdcr2nl(IOQ*, int);
int		kbdputc(IOQ*, int);
void		kbdrepeat(int);
long		keyread(char*, int, long);
long		keywrite(char*, int);
void		kickpager(void);
int		kprint(char*, ...);
void		kproc(char*, void(*)(void*), void*);


@@ 266,6 278,7 @@ void		unmount(Chan*, Chan*);
void		urpfillstats(Chan*, char*, int);
void		userinit(void);
ulong		userpc(void);
long		userwrite(char*, int);
void		validaddr(ulong, ulong, int);
void*		vmemchr(void*, int, int);
void		wakeup(Rendez*);

M port/stfcall.c => port/stfcall.c +4 -6
@@ 24,14 24,14 @@ static uchar msglen[256] =
{
	[Tnop]		3,
	[Rnop]		3,
	[Tsession]	3,
	[Rsession]	3,
	[Tsession]	3+CHALLEN,
	[Rsession]	3+NAMELEN+DOMLEN+CHALLEN,
	[Terror]	0,
	[Rerror]	67,
	[Tflush]	5,
	[Rflush]	3,
	[Tattach]	89,
	[Rattach]	13,
	[Tattach]	5+2*NAMELEN+TICKETLEN+AUTHENTLEN,
	[Rattach]	13+AUTHENTLEN,
	[Tclone]	7,
	[Rclone]	5,
	[Twalk]		33,


@@ 54,8 54,6 @@ static uchar msglen[256] =
	[Rwstat]	5,
	[Tclwalk]	35,
	[Rclwalk]	13,
	[Tauth]		69,
	[Rauth]		35,
};

static void

M port/sysfile.c => port/sysfile.c +0 -12
@@ 85,13 85,6 @@ openmode(ulong o)
}

long
sysfsession(ulong *arg)
{
	USED(arg);
	return 0;
}

long
syspipe(ulong *arg)
{
	int fd[2];


@@ 442,7 435,6 @@ bindmount(ulong *arg, int ismount)
	struct{
		Chan	*chan;
		char	*spec;
		char	*serv;
	}bogus;

	flag = arg[2];


@@ 462,11 454,7 @@ bindmount(ulong *arg, int ismount)
			error(Ebadarg);

		bogus.spec = (char*)arg[3];
		validaddr(arg[4], 1, 0);
		if(vmemchr((char*)arg[4], '\0', NAMELEN) == 0)
			error(Ebadarg);

		bogus.serv = (char*)arg[4];
		ret = devno('M', 0);
		c0 = (*devtab[ret].attach)((char*)&bogus);


M port/sysproc.c => port/sysproc.c +0 -4
@@ 42,8 42,6 @@ sysrfork(ulong *arg)
			p->pgrp = newpgrp();
			if(flag & RFNAMEG)
				pgrpcpy(p->pgrp, opg);
			else
				*p->pgrp->crypt = *opg->crypt;
			closepgrp(opg);
		}
		if(flag & (RFENVG|RFCENVG)) {


@@ 126,8 124,6 @@ sysrfork(ulong *arg)
		p->pgrp = newpgrp();
		if(flag & RFNAMEG)
			pgrpcpy(p->pgrp, parent->pgrp);
		else
			*p->pgrp->crypt = *parent->pgrp->crypt;
	}
	else {
		p->pgrp = parent->pgrp;

M port/systab.h => port/systab.h +3 -3
@@ 13,7 13,7 @@ Syscall sysalarm;
Syscall sysexec;
Syscall sysexits;
Syscall sysfsession;
Syscall sys_x2;
Syscall sysfauth;
Syscall sysfstat;
Syscall syssegbrk;
Syscall sysmount;


@@ 53,7 53,7 @@ Syscall *systab[]={
	[EXEC]		sysexec,
	[EXITS]		sysexits,
	[FSESSION]	sysfsession,
	[_X2]		sysdeath,
	[FAUTH]		sysfauth,
	[FSTAT]		sysfstat,
	[SEGBRK]	syssegbrk,
	[MOUNT]		sysmount,


@@ 93,7 93,7 @@ char *sysctab[]={
	[EXEC]		"Exec",
	[EXITS]		"Exits",
	[FSESSION]	"Fsession",
	[_X2]		"_x2",
	[FAUTH]		"Fauth",
	[FSTAT]		"Fstat",
	[SEGBRK]	"Segbrk",
	[MOUNT]		"Mount",