V9/netb/src/perm.c

Compare this file to the similar file:
Show the results in this format:

/* all the permission stuff. */
#include "share.h"
#include "pwd.h"
#include "grp.h"

typedef struct {
	int huid, cuid;
} tuid;
tuid *t, *g;
int tcnt, gcnt;
int primes[] = {23, 47, 97, 199, 397, 797, 1597, 3191, 6397, 12799, 31991, 0};
int *uhhash, *uchash, uhp, *ghhash, *gchash, ghp;
int otherok = 1;	/* default policy */
int pfd;	/* temporary file descriptor */
char *exbf, *realexbf;	/* exception buffer */
char clientname[128] = "\n";	/* the client's name, newline terminated */

clientuid()	/* from client to host */
{	int j;
	if(client.uid < 0)
		return(-1);
	for(j = client.uid % uhp; uchash[j] != -1; j++)
		if(t[uchash[j]].cuid == client.uid)
			return(t[uchash[j]].huid);
	return(-1);
}

clientgid()	/* from client to host */
{	int j;
	if(client.gid < 0)
		return(-1);
	for(j = client.gid % ghp; gchash[j] != -1; j++)
		if(g[gchash[j]].cuid == client.gid)
			return(g[gchash[j]].huid);
	return(-1);
}

hostuid(n)	/* host to client */
{	int j;
	if(n < 0)
		return(-1);
	for(j = n % uhp; uhhash[j] != -1; j++)
		if(t[uhhash[j]].huid == n)
			return(t[uhhash[j]].cuid);
	return(-1);
}

hostgid(n)	/* host to client */
{	int j;
	if(n < 0)
		return(-1);
	for(j = n % ghp; ghhash[j] != -1; j++)
		if(g[ghhash[j]].huid == n)
			return(g[ghhash[j]].cuid);
	return(-1);
}

isowner(p)
struct stat *p;
{
	if(clientuid() == p->st_uid)
		return(1);
	return(0);
}

searchperm()
{	struct stat stb;
	if(stat(nmbuf, &stb) < 0) {
		client.errno = errno;
		return(1);
	}
	if(clientuid() == stb.st_uid && (stb.st_mode & 0100))
		return(0);
	if(clientgid() == stb.st_gid && (stb.st_mode & 010))
		return(0);
	if((stb.st_mode & 1) && (otherok || clientuid() != -1))
		return(0);
	return(1);
}

writeperm()
{	struct stat stb;
	if(stat(nmbuf, &stb) < 0) {
		client.errno = errno;
		return(1);
	}
	if(clientuid() == stb.st_uid && (stb.st_mode & 0200))
		return(0);
	if(clientgid() == stb.st_gid && (stb.st_mode & 020))
		return(0);
	if((stb.st_mode & 2) && (otherok || clientuid() != -1))
		return(0);
	client.errno = EPERM;
	return(1);
}

dirwriteperm()
{	int n;
error("dw (%d,%d)\n", clientuid(), clientgid());
	if(!slash)
		return(1);	/* this can't happen? */
	if(clientuid() == -1 || clientgid() == -1) {
		client.errno = EPERM;
		return(1);	/* too bad bozo */
	}
	*slash = 0;
	n = writeperm();
	*slash = '/';
	return(n);
}

/* hostdev translates from host's devs to client's */
hostdev(n)
{	int i;
	for(i = 0; i < ndev; i++)
		if(devs[i].hdev == n)
			return(devs[i].cdev);
	error("hostdev: 0x%x not found\n", n);
	client.errno = ENXIO;
	return(0);
}

/* clientdev translates from client's to host's */
clientdev(n)
{	int i;
	for(i = 0; i < ndev; i++)
		if(devs[i].cdev == n)
			return(devs[i].hdev);
	debug("clientdev: 0x%x not found\n", n);
	client.errno = ENXIO;
	return(0);
}

getuids()
{	int i, j;
	char msg[16];
	/* scan host passwd file for count */
	tcnt = cntpasswd();
	t = (tuid *) malloc(tcnt * sizeof(tuid));
	i = xread(cfd, inbuf, inlen);
	if(i != inlen)
		fatal("getuids read %d (%d)\n", i, errno);
	/* decode and ack */
	msg[0] = 2;
	if(write(cfd, msg, 1) != 1)
		fatal("getuid ack failed (%d)\n", errno);
	/* and match with host passwd */
	fillpasswd();
	for(i = 0; primes[i] && primes[i] < 2 * tcnt; i++)
		;
	if(primes[i] == 0)
		fatal("tcnt %d too big for hashtable %d\n", tcnt, primes[i-1]);
	uhp = primes[i];
	uhhash = (int *) malloc((uhp + 4) * sizeof(int));
	uchash = (int *) malloc((uhp + 4) * sizeof(int));
	/* what's the chance the last 3 items will fill? */
	for(i = 0; i < uhp + 4; i++)
		uhhash[i] = uchash[i] = -1;
	for(i = 0; i < tcnt; i++) {
		j = t[i].huid % uhp;
		while(uhhash[j] != -1)
			j++;
		if(j >= uhp + 3)	/* guarantee sentinel at end of hash tables */
			fatal("uhhash overflow!\n");
		uhhash[j] = i;

		j = t[i].cuid % uhp;
		while(uchash[j] != -1)
			j++;
		if(j >= uhp + 3)
			fatal("uchash overflow!\n");
		uchash[j] = i;
	}
}

getgids()
{	int i, j;
	char msg[16];
	/* scan host group file for count */
	gcnt = cntgroups();
	g = (tuid *) malloc(gcnt * sizeof(tuid));
	i = xread(cfd, inbuf, inlen);
	if(i != inlen)
		fatal("getgids read %d (%d)\n", i, errno);
	/* decode and ack */
	msg[0] = 3;
	if(write(cfd, msg, 1) != 1)
		fatal("getgid ack failed (%d)\n", errno);
	/* and match with host passwd */
	fillgroups();
	for(i = 0; primes[i] && primes[i] < 2 * gcnt; i++)
		;
	if(primes[i] == 0)
		fatal("gcnt %d too big for hashtable %d\n", gcnt, primes[i-1]);
	ghp = primes[i];
	ghhash = (int *) malloc((ghp + 4) * sizeof(int));
	gchash = (int *) malloc((ghp + 4) * sizeof(int));
	/* what's the chance the last 3 items will fill? */
	for(i = 0; i < ghp + 4; i++)
		ghhash[i] = gchash[i] = -1;
	for(i = 0; i < gcnt; i++) {
		j = g[i].huid % ghp;
		while(ghhash[j] != -1)
			j++;
		if(j >= ghp + 3) /* guarantee sentinel at end of hash tables */
			fatal("ghhash overflow!\n");
		ghhash[j] = i;

		j = g[i].cuid % ghp;
		while(gchash[j] != -1)
			j++;
		if(j >= ghp + 3)
			fatal("gchash overflow!\n");
		gchash[j] = i;
	}
}

cntpasswd()
{	struct passwd *p, *getpwent();
	int m = 0;
	while(p = getpwent())
		m++;
	setpwent();	/* leave it set for fillpasswd() */
	return(m);
}

cntgroups()
{	struct group *g, *getgrent();
	int m = 0;
	while(g = getgrent()) {
		m++;
	}
	setgrent();	/* leave it set for fillgroups() */
	return(m);
}

char *
clientline(s)
char *s;
{	char *p;
	if(!s || !*s)
		return(0);
	for(p = s; *p; ) {
		if(strncmp(p, "client ", 7) == 0 || strncmp(p, "client\t", 7) == 0)
			return(p);
		while(*p++ != '\n');
			;
	}
	return(p);
}

getexcepts()
{	char *p, *q, *r;
	struct stat stb;
	pfd = open("/usr/netb/except", 0);
	if(pfd < 0 || fstat(pfd, &stb) < 0) {
		error("danger!!! can't find /usr/netb/except, but proceeding\n");
fakeit:
		exbf = (char *) malloc(1);
		realexbf = exbf;
		*exbf = 0;
		return;
	}
	exbf = (char *) malloc(stb.st_size + 1);
	realexbf = exbf;
	if(read(pfd, exbf, stb.st_size) != stb.st_size) {
		error("danger!!! can't read /usr/netb/except, but proceeding\n");
		free(exbf);
		goto fakeit;
	}
	close(pfd);
	/* now find the section for this client */
	for(q = 0, p = clientline(exbf); *p; p = clientline(p)) {
		if(q) {
			*p = 0;
			exbf = q;
			error("found excepts for client %s");
			return;
		}
		r = p + 6;	/* skip across "client " */
		while(*r == ' ' || *r == '\t')
			r++;
		if(strncmp(r, clientname, strlen(clientname)) == 0)
			q = p;
		while(*p++ != '\n')
			;
	}
	error("warning!!! no match for client %s", clientname);
	/* look for the default client */
	for(q = 0, p = clientline(exbf); *p && !q; p = clientline(p+1)) {
		r = p + 6;	/* skip across "client " */
		while(*r == ' ' || *r == '\t')
			r++;
		if(*r == '*' && r[1] == '\n')
			q = p;
	}
	if(q) {
		exbf = q;
		error("using default client info\n");
		return;
	}
	error("warning!!! no default client info, proceeding anyway\n");
}

char *
findexcept(tag, s)
char *tag, *s;
{	char *p, *q;
	int n;
	n = strlen(tag);
	p = exbf;
loop:
	if(*p == 0)
		return(s);
	if(strncmp(tag, p, n) != 0) {
eol:
		while(*p && *p++ != '\n')
			;
		goto loop;
	}
	for(p += n; *p == ' ' || *p == '\t'; p++)
		;	/* skip the tag and whitespace */
	for(q = s; *p == *q; p++, q++)
		;
	if(*q != 0 || *p != '=')
		goto eol;
	if(p[1] == ' ' || p[1] == '\t' || p[1] == '\n')
		return(0);	/* client not allowed */
	return(p+1);
}

doneexcepts()
{	char *s;
	s = findexcept("param", "otherok");
	if(s && *s == '0')
		otherok = 0;
	error("otherok %d\n", otherok);
	/* umask could be settable too */
	umask(0);
	free(realexbf);
	realexbf = exbf = (char *) -1;	/* dereference that */
}

char *
findid(t, s)
char *t, *s;
{	char *p, *q;
	s = findexcept(t, s);
	if(!s)
		return(0);
	p = (char *)inbuf;
loop:
	if(*p == 0)
		return(0);
	for(q = s; *p == *q; p++, q++)
		;
	if((*q == 0 || *q == ' ' || *q == '\t' || *q == '\n') && *p == ' ')
		return(p+1);
	while(*p && *p != '\n')
		p++;
	if(*p == '\n')
		p++;
	goto loop;
}

fillpasswd()	/* quadratic */
{	struct passwd *p, *getpwent();
	char *s;
	int i = 0;
	while(p = getpwent()) {
		s = findid("uid", p->pw_name);
		if(s == 0)
			continue;
		t[i].huid = p->pw_uid;
		t[i].cuid = atoi(s);
		i++;
	}
	error("matched %d passwds out of %d\n", i, tcnt);
	tcnt = i;
	endpwent();
}

fillgroups()	/* quadratic */
{	struct group *p, *getgrent();
	char *s;
	int i = 0;
	while(p = getgrent()) {
		s = findid("gid", p->gr_name);
		if(s == 0)
			continue;
		g[i].huid = p->gr_gid;
		g[i].cuid = atoi(s);
		i++;
	}
	error("matched %d groups out of %d\n", i, gcnt);
	gcnt = i;
	endgrent();
}