diff options
Diffstat (limited to 'appl/cmd/rcmd.b')
| -rw-r--r-- | appl/cmd/rcmd.b | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/appl/cmd/rcmd.b b/appl/cmd/rcmd.b new file mode 100644 index 00000000..43fe9078 --- /dev/null +++ b/appl/cmd/rcmd.b @@ -0,0 +1,170 @@ +implement Rcmd; + +include "sys.m"; +include "draw.m"; +include "arg.m"; +include "keyring.m"; +include "security.m"; + +Rcmd: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +DEFAULTALG := "none"; +sys: Sys; +auth: Auth; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->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] [-a alg] [-e exportpath] tcp!mach cmd"); + while((o := arg->opt()) != 0) + case o { + 'a' => + alg = arg->earg(); + 'A' => + doauth = 0; + 'e' => + 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"; + } + + (ok, c) := sys->dial(netmkaddr(addr, "tcp", "rstyx"), nil); + if(ok < 0) + error(sys->sprint("dial server failed: %r")); + + 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]; +} + +netmkaddr(addr, net, svc: string): string +{ + if(net == nil) + net = "net"; + (n, l) := sys->tokenize(addr, "!"); + if(n <= 1){ + if(svc== nil) + return sys->sprint("%s!%s", net, addr); + return sys->sprint("%s!%s!%s", net, addr, svc); + } + if(svc == nil || n > 2) + return addr; + return sys->sprint("%s!%s", addr, svc); +} + +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"; +} |
