code: 9ferno

ref: da7d6df6faf18e289fe0f3f61524dcc7fddeef18
dir: /appl/cmd/rcmd.b/

View raw version
implement Rcmd;

include "sys.m";
include "draw.m";
include "arg.m";
include "keyring.m";
include "dial.m";
include "security.m";

Rcmd: module
{
	init:	fn(ctxt: ref Draw->Context, argv: list of string);
};

DEFAULTALG := "none";
sys: Sys;
auth: Auth;
dial: Dial;

init(nil: ref Draw->Context, argv: list of string)
{
	sys = load Sys Sys->PATH;
	dial = load Dial Dial->PATH;
	if(dial == nil)
		badmodule(Dial->PATH);
	arg := load Arg Arg->PATH;
	if(arg == nil)
		badmodule(Arg->PATH);
	arg->init(argv);
	alg: string;
	doauth := 1;
	exportpath := "/";
	keyfile: string;
	arg->setusage("rcmd [-A] [-f keyfile] [-e alg] [-x exportpath] tcp!mach cmd");
	while((o := arg->opt()) != 0)
		case o {
		'e' or 'a' =>
			alg = arg->earg();
		'A' =>
			doauth = 0;
		'x' =>
			exportpath = arg->earg();
			(n, nil) := sys->stat(exportpath);
			if (n == -1 || exportpath == nil)
				arg->usage();
		'f' =>
			keyfile = arg->earg();
			if (! (keyfile[0] == '/' || (len keyfile > 2 &&  keyfile[0:2] == "./")))
				keyfile = "/usr/" + user() + "/keyring/" + keyfile;
		*   =>
			arg->usage();
		}

	argv = arg->argv();
	if(argv == nil)
		arg->usage();
	arg = nil;

	if (doauth && alg == nil)
		alg = DEFAULTALG;

	addr := hd argv;
	argv = tl argv;

	args := "";
	while(argv != nil){
		args += " " + hd argv;
		argv = tl argv;
	}
	if(args == "")
		args = "sh";

	kr: Keyring;
	au: Auth;
	if (doauth) {
		kr = load Keyring Keyring->PATH;
		if(kr == nil)
			badmodule(Keyring->PATH);
		au = load Auth Auth->PATH;
		if(au == nil)
			badmodule(Auth->PATH);
		if (keyfile == nil)
			keyfile = "/usr/" + user() + "/keyring/default";
	}

	c := dial->dial(dial->netmkaddr(addr, "tcp", "rstyx"), nil);
	if(c == nil)
		error(sys->sprint("dial %s failed: %r", addr));

	fd := c.dfd;
	if (doauth) {
		ai := kr->readauthinfo(keyfile);
		#
		# let auth->client handle nil ai
		# if(ai == nil){
		#	sys->fprint(stderr(), "rcmd: certificate for %s not found\n", addr);
		#	raise "fail:no certificate";
		# }
		#

		err := au->init();
		if(err != nil)
			error(err);

		(fd, err) = au->client(alg, ai, c.dfd);
		if(fd == nil){
			sys->fprint(stderr(), "rcmd: authentication failed: %s\n", err);
			raise "fail:auth failed";
		}
	}
	t := array of byte sys->sprint("%d\n%s\n", len (array of byte args)+1, args);
	if(sys->write(fd, t, len t) != len t){
		sys->fprint(stderr(), "rcmd: cannot write arguments: %r\n");
		raise "fail:bad arg write";
	}

	if(sys->export(fd, exportpath, sys->EXPWAIT) < 0) {
		sys->fprint(stderr(), "rcmd: export: %r\n");
		raise "fail:export failed";
	}
}

exists(f: string): int
{
	(ok, nil) := sys->stat(f);
	return ok >= 0;
}

user(): string
{
	sys = load Sys Sys->PATH;

	fd := sys->open("/dev/user", sys->OREAD);
	if(fd == nil)
		return "";

	buf := array[128] of byte;
	n := sys->read(fd, buf, len buf);
	if(n < 0)
		return "";

	return string buf[0:n];	
}

stderr(): ref Sys->FD
{
	return sys->fildes(2);
}

badmodule(p: string)
{
	sys->fprint(stderr(), "rcmd: cannot load %s: %r\n", p);
	raise "fail:bad module";
}

error(e: string)
{
	sys->fprint(stderr(), "rcmd: %s\n", e);
	raise "fail:errors";
}