1874 lines · 34.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include	"all.h" #define MSIZE	(MAXDAT+128) static voidseterror(Fcall *ou, int err){ 	if(0 <= err && err < MAXERR)		ou->ename = errstring[err];	else		ou->ename = "unknown error";} static intfsversion(Chan* chan, Fcall* f, Fcall* r){	if(f->msize < MSIZE)		r->msize = f->msize;	else		r->msize = MSIZE;	/*	 * Should check the '.' stuff here.	 * What happens if Tversion has already been seen?	 */	if(strcmp(f->version, VERSION9P) == 0){		r->version = VERSION9P;		chan->msize = r->msize;	}else		r->version = "unknown"; 	fileinit(chan);	return 0;} char *keyspec = "proto=p9any role=server"; static intfsauth(Chan *chan, Fcall *f, Fcall *r){	int err, fd;	char *aname;	File *file;	int afd;	AuthRpc *rpc; 	err = 0;	if(chan == cons.srvchan)		return Eauthmsg;	file = filep(chan, f->afid, 1);	if(file == nil)		return Efidinuse; 	/* forget any previous authentication */	file->cuid = 0; 	if(access("/mnt/factotum", 0) < 0)		if((fd = open("/srv/factotum", ORDWR)) >= 0)			mount(fd, -1, "/mnt", MBEFORE, ""); 	afd = open("/mnt/factotum/rpc", ORDWR);	if(afd < 0){		err = Esystem;		goto out;	}	rpc = auth_allocrpc(afd);	if(rpc == nil){		close(afd);		err = Esystem;		goto out;	}	file->rpc = rpc;	if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){		err = Esystem;		goto out;	} 	aname = f->aname;	if(!aname[0])		aname = "main";	file->fs = fsstr(aname);	if(file->fs == nil){		err = Ebadspc;		goto out;	}	file->uid = strtouid(f->uname);	if(file->uid < 0){		err = Ebadu;		goto out;	}	file->qid.path = 0;	file->qid.vers = 0;	file->qid.type = QTAUTH;	r->qid = file->qid; out:	if(file != nil){		qunlock(file);		if(err != 0)			freefp(file);	}	return err;} intauthread(File *file, uchar *data, int count){	AuthInfo *ai;	AuthRpc *rpc;	int rv; 	rpc = file->rpc;	if(rpc == nil)		return -1; 	rv = auth_rpc(rpc, "read", nil, 0);	switch(rv){	case ARdone:		ai = auth_getinfo(rpc);		if(ai == nil)			return -1;		if(chat)			print("authread identifies user as %s\n", ai->cuid);		file->cuid = strtouid(ai->cuid);		auth_freeAI(ai);		if(file->cuid == 0)			return -1;		if(chat)			print("%s is a known user\n", ai->cuid);		return 0;	case ARok:		if(count < rpc->narg)			return -1;		memmove(data, rpc->arg, rpc->narg);		return rpc->narg;	case ARphase:		return -1;	default:		return -1;	}} intauthwrite(File *file, uchar *data, int count){	int ret; 	ret = auth_rpc(file->rpc, "write", data, count);	if(ret != ARok)		return -1;	return count;} voidmkqid9p1(Qid9p1* qid9p1, Qid* qid){	if(qid->path & 0xFFFFFFFF00000000LL)		panic("mkqid9p1: path %lluX\n", qid->path);	qid9p1->path = qid->path & 0xFFFFFFFF;	if(qid->type & QTDIR)		qid9p1->path |= QPDIR;	qid9p1->version = qid->vers;} voidauthfree(File *fp){	if(fp->rpc != nil){		close(fp->rpc->afd);		free(fp->rpc);		fp->rpc = nil;	}} voidmkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode){	qid->path = (ulong)(qid9p1->path & ~QPDIR);	qid->vers = qid9p1->version;	qid->type = 0;	if(mode & DDIR)		qid->type |= QTDIR;	if(mode & DAPND)		qid->type |= QTAPPEND;	if(mode & DLOCK)		qid->type |= QTEXCL;} static intcheckattach(Chan *chan, File *afile, File *file, Filsys *fs){	uchar buf[1]; 	if(chan == cons.srvchan || chan == cons.chan)		return 0; 	/* if no afile, this had better be none */	if(afile == nil){		if(file->uid == 0){			if(!allownone && !chan->authed)				return Eauth;			return 0;		}		return Eauth;	} 	/* otherwise, we'ld better have a usable cuid */	if(!(afile->qid.type&QTAUTH))		return Eauth;	if(afile->uid != file->uid || afile->fs != fs)		return Eauth;	if(afile->cuid <= 0){		if(authread(afile, buf, 0) != 0)			return Eauth;		if(afile->cuid <= 0)			return Eauth;	}	file->uid = afile->cuid; 	/* once someone has authenticated on the channel, others can become none */	chan->authed = 1; 	return 0;}		 static intfsattach(Chan* chan, Fcall* f, Fcall* r){	char *aname;	Iobuf *p;	Dentry *d;	File *file;	File *afile;	Filsys *fs;	long raddr;	int error, u; 	aname = f->aname;	if(!aname[0])	/* default */		aname = "main";	p = nil;	afile = filep(chan, f->afid, 0);	file = filep(chan, f->fid, 1);	if(file == nil){		error = Efidinuse;		goto out;	} 	u = -1;	if(chan != cons.chan){		if(strcmp(f->uname, "adm") == 0){			error = Eauth;			goto out;		}		u = strtouid(f->uname);		if(u < 0){			error = Ebadu;			goto out;		}	}	file->uid = u; 	fs = fsstr(aname);	if(fs == nil){		error = Ebadspc;		goto out;	} 	if(error = checkattach(chan, afile, file, fs))		goto out; 	raddr = getraddr(fs->dev);	p = getbuf(fs->dev, raddr, Bread);	d = getdir(p, 0);	if(d == nil || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(iaccess(file, d, DEXEC)){		error = Eaccess;		goto out;	}	if(file->uid == 0 && isro(fs->dev)) {		/*		 * 'none' not allowed on dump		 */		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD);	mkqid(&file->qid, d, 1);	file->fs = fs;	file->addr = raddr;	file->slot = 0;	file->open = 0;	freewp(file->wpath);	file->wpath = 0; 	r->qid = file->qid; //	if(cons.flags & attachflag)//		print("9p2: attach %s %T to \"%s\" C%d\n",//			chan->whoname, chan->whotime, fs->name, chan->chan); out://	if((cons.flags & attachflag) && error)//		print("9p2: attach %s %T SUCK EGGS --- %s\n",//			f->uname, time(), errstr[error]);	if(p != nil)		putbuf(p);	if(afile != nil)		qunlock(afile);	if(file != nil){		qunlock(file);		if(error)			freefp(file);	} 	return error;} static intfsflush(Chan* chan, Fcall*, Fcall*){	runlock(&chan->reflock);	wlock(&chan->reflock);	wunlock(&chan->reflock);	rlock(&chan->reflock); 	return 0;} static voidclone(File* nfile, File* file){	Wpath *wpath; 	nfile->qid = file->qid; 	lock(&wpathlock);	nfile->wpath = file->wpath;	for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)		wpath->refs++;	unlock(&wpathlock); 	nfile->fs = file->fs;	nfile->addr = file->addr;	nfile->slot = file->slot;	nfile->uid = file->uid;	nfile->cuid = 0;	nfile->open = file->open & ~FREMOV;} static intwalkname(File* file, char* wname, Qid* wqid){	Wpath *w;	Iobuf *p, *p1;	Dentry *d, *d1;	int error, slot;	long addr, qpath; 	p = p1 = nil; 	/*	 * File must not have been opened for I/O by an open	 * or create message and must represent a directory.	 */	if(file->open != 0){		error = Emode;		goto out;	} 	p = getbuf(file->fs->dev, file->addr, Bread);	if(p == nil || checktag(p, Tdir, QPNONE)){		error = Edir1;		goto out;	}	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){		error = Ealloc;		goto out;	}	if(!(d->mode & DDIR)){		error = Edir1;		goto out;	}	if(error = mkqidcmp(&file->qid, d))		goto out; 	/*	 * For walked elements the implied user must	 * have permission to search the directory.	 */	if(file->cp != cons.chan && iaccess(file, d, DEXEC)){		error = Eaccess;		goto out;	}	accessdir(p, d, FREAD); 	if(strcmp(wname, ".") == 0){setdot:		if(wqid != nil)			*wqid = file->qid;		goto out;	}	if(strcmp(wname, "..") == 0){		if(file->wpath == 0)			goto setdot;		putbuf(p);		p = nil;		addr = file->wpath->addr;		slot = file->wpath->slot;		p1 = getbuf(file->fs->dev, addr, Bread);		if(p1 == nil || checktag(p1, Tdir, QPNONE)){			error = Edir1;			goto out;		}		if((d1 = getdir(p1, slot)) == nil || !(d1->mode & DALLOC)){			error = Ephase;			goto out;		}		lock(&wpathlock);		file->wpath->refs--;		file->wpath = file->wpath->up;		unlock(&wpathlock);		goto found;	} 	for(addr = 0; ; addr++){		if(p == nil){			p = getbuf(file->fs->dev, file->addr, Bread);			if(p == nil || checktag(p, Tdir, QPNONE)){				error = Ealloc;				goto out;			}			d = getdir(p, file->slot);			if(d == nil ||  !(d->mode & DALLOC)){				error = Ealloc;				goto out;			}		}		qpath = d->qid.path;		p1 = dnodebuf1(p, d, addr, 0);		p = nil;		if(p1 == nil || checktag(p1, Tdir, qpath)){			error = Eentry;			goto out;		}		for(slot = 0; slot < DIRPERBUF; slot++){			d1 = getdir(p1, slot);			if(!(d1->mode & DALLOC))				continue;			if(strncmp(wname, d1->name, NAMELEN) != 0)				continue;			/*			 * update walk path			 */			if((w = newwp()) == nil){				error = Ewalk;				goto out;			}			w->addr = file->addr;			w->slot = file->slot;			w->up = file->wpath;			file->wpath = w;			slot += DIRPERBUF*addr;			goto found;		}		putbuf(p1);		p1 = nil;	} found:	file->addr = p1->addr;	mkqid(&file->qid, d1, 1);	putbuf(p1);	p1 = nil;	file->slot = slot;	if(wqid != nil)		*wqid = file->qid; out:	if(p1 != nil)		putbuf(p1);	if(p != nil)		putbuf(p); 	return error;} static int

Lines 1–500 of 1874.