Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/sys/src/cmd/bns/auth.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Yet more code duplicated to perform the amount op.
 */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <auth.h>
#include <ip.h>
#include "names.h"
#include "vols.h"

static int
agetfrep(int fd, Frpc* fop)
{
	int r;

	r = getfrep(fd, fop);
	if (r > 0 || r == -1)
		Dbgprint(fop->fid, "   <= %F\n", &fop->r);
	return r;
}

static long
fswrite(int fd, int fid, Frpc* fop, void* a, long n)
{
	fop->f.tag = 0xb;
	fop->f.type= Twrite;
	fop->f.fid = fid;
	fop->f.data = a;
	fop->f.count = n;
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 ||
	    fop->r.type != Rwrite || fop->r.tag != fop->f.tag)
		return -1;
	return fop->r.count;
}

static long
fsread(int fd, int fid, Frpc* fop, void* a, long n)
{
	fop->f.tag = 0xc;
	fop->f.type= Tread;
	fop->f.fid = fid;
	fop->f.count = n;
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 ||
	    fop->r.type != Rread || fop->r.tag != fop->f.tag)
		return -1;
	memmove(a, fop->r.data, fop->r.count);
	return fop->r.count;
}

static long
fsclose(int fd, int fid, Frpc* fop)
{
	fop->f.tag = 0xd;
	fop->f.type= Tclunk;
	fop->f.fid = fid;
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 ||
	    fop->r.type != Rclunk || fop->r.tag != fop->f.tag)
		return -1;
	return 0;
}

static int
fsattach(int fd, int fid, int afid, char* spec, Frpc* fop, Qid* q)
{
	fop->f.tag = 0xe;
	fop->f.type= Tattach;
	fop->f.fid = fid;
	fop->f.afid= afid;
	fop->f.uname = getuser();
	fop->f.aname = spec;
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 ||
	    fop->r.type != Rattach || fop->r.tag != fop->f.tag)
		return -1;
	*q = fop->r.qid;
	return 0;
}

static char* anames[] = {
	"ok", "done", "error", "needkey", "badkey", "writenext", "toosmall", "toobig",
	"rpcfailure", "phase" };

static AuthInfo*
fsfauth_proxy(int fsfd, int afid, Frpc* fop, AuthRpc *rpc, char* params)
{
	char *buf;
	int m, n, ret;
	AuthInfo *a;
	char oerr[ERRMAX];
	int	id;

	rerrstr(oerr, sizeof oerr);
	werrstr("UNKNOWN AUTH ERROR");

	assert(rpc);
	if(auth_rpc(rpc, "start", params, strlen(params)) != ARok){
		werrstr("fauth_proxy start: %r");
		return nil;
	}

	buf = emalloc(AuthRpcMax);
	for(;;){
		id = auth_rpc(rpc, "read", nil, 0);
		switch(id){
		case ARdone:
			free(buf);
			a = auth_getinfo(rpc);
			errstr(oerr, sizeof oerr);	/* no error, restore whatever was there */
			return a;
		case ARok:
			if(fswrite(fsfd, afid, fop, rpc->arg, rpc->narg) != rpc->narg){
				werrstr("auth_proxy write fd: %r");
				goto Error;
			}
			break;
		case ARphase:
			n = 0;
			memset(buf, 0, AuthRpcMax);
			while((ret = auth_rpc(rpc, "write", buf, n)) == ARtoosmall){
				if(atoi(rpc->arg) > AuthRpcMax)
					break;
				m = fsread(fsfd, afid, fop, buf+n, atoi(rpc->arg)-n);
				if(m <= 0){
					if(m == 0)
						werrstr("auth_proxy short read: %s", buf);
					goto Error;
				}
				n += m;
			}
			if (ret != ARok){
				goto Error;
			}
			break;
		default:
			werrstr("auth_proxy rpc: %r");
			goto Error;
		}
	}
Error:
	free(buf);
	return nil;
}


static AuthInfo*
fsauth_proxy(int fsfd, int afid, Frpc* fop, char* params)
{
	AuthInfo *ai;
	AuthRpc *rpc;
	int	afd;

	quotefmtinstall();	/* just in case */
	afd = open("/mnt/factotum/rpc", ORDWR);
	if(afd < 0){
		// Try mounting it.
		afd = open("#s/factotum", ORDWR);
		if (afd < 0){
			return nil;
		}
		mount(afd, -1, "/mnt", MREPL, "");
		afd = open("/mnt/factotum/rpc", ORDWR);
		if (afd < 0){
			return nil;
		}
	}
	rpc = auth_allocrpc(afd);
	if(rpc == nil) {
		close(afd);
		return nil;
	}
	ai = fsfauth_proxy(fsfd, afid, fop, rpc, params);
	auth_freerpc(rpc);
	close(afd);
	return ai;
}

static int
authfsfd(int fd, char* spec, Frpc* fop)
{
	AuthInfo*ai;
	int	afid;

	fop->f.tag = 0xb;
	fop->f.type= Tauth;
	fop->f.afid = getfidnr();
	fop->f.uname = getuser();
	fop->f.aname = spec;
	afid = -1;
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0)
		goto fail;
	if (fop->r.type == Rerror)  // no auth required.
		goto done;
	if (fop->r.type != Rauth || fop->r.tag != fop->f.tag)
		goto fail;
	else
		afid = fop->f.afid;
	/* The next call depends on linking against our own
	 * fauth_proxy function, which speaks 9P to the server
	 * instead of using the kernel.
	 */
	ai = fsauth_proxy(fd, afid, fop, "proto=p9any role=client");
	if (0 && ai == nil) // Debugging this
		goto fail;
	auth_freeAI(ai);
done:
	return afid;
fail:
	close(fd);
	return -1;

}

static int
fsversion(int fd, Frpc* fop)
{
	fop->f.tag = NOTAG;
	fop->f.type= Tversion;
	fop->f.msize= Maxmsglen;
	fop->f.version = "9P2000";
	if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0){
		vdprint(2, "can't RPC Tversion: %r\n");
		return -1;
	}
	if (fop->r.tag != NOTAG || fop->r.type != Rversion){
		vdprint(2, "bad reply for Tversion");
		return -1;
	}
	if (strcmp(fop->r.version, "9P2000")){
		vdprint(2, "bad server version\n");
		return -1;
	}
	if (fop->r.msize < Maxmsglen)
		msglen = fop->r.msize;
	return 1;
}

static int
dialfs(Fs* fs)
{
	int	fd, cfd;
	char	dir[50];
	char*	s;

	cfd = -1;
	if (fs->addr[0] == '#' || fs->addr[0] == '/')
		fd = open(fs->addr, ORDWR);
	else {
		s=smprint("/net/%s", fs->addr);
		fd = dial(s, 0, dir, &cfd);
		free(s);
		if (cfd != -1){
			fprint(cfd, "keepalive 2000\n");
			close(cfd);
		}
	}
	return fd;
}

int
amountfs(Fs* fs)
{
	int	fd, afid, r;
	Frpc*	fop;
	int	doversion;
	Dir*	d;

	fd = dialfs(fs);
	if (fd < 0){
		vdprint(2, "%s: can't dial %s: %r\n", argv0, fs->addr);
		return 0;
	}
	if (fs->addr[0] != '#' && fs->addr[0] != '/')
		doversion = 1;
	else {
		d = dirfstat(fd);
		if (d == nil)
			return 0;
		doversion = (d->qid.path != fs->fdqid.path);
		fs->fdqid = d->qid;
		free(d);
	}
	fop = rpcalloc();
	if (doversion && fsversion(fd, fop) < 0){
		vdprint(2, "%s: %s: bad fversion\n", argv0, fs->addr);
		close(fd);
		rpcfree(fop);
		return 0;
	}
	afid = authfsfd(fd, fs->spec, fop);
	if (fsattach(fd, fs->fid->snr, afid, fs->spec, fop, &fs->fid->qid) < 0){
		vdprint(2, "%s: attach failed: %s\n", argv0, fs->addr);
		close(fd); // afid will be collected by the server.
		r = 0;
	} else {
		if (afid >= 0)
			fsclose(fd, afid, fop);
		fs->fid->qid.path |= fs->qid.path;
		fs->fd = fd;	// make it official.
		r = 1;
	}
	rpcfree(fop);
	return r;
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].