diff options
Diffstat (limited to 'appl/cmd/import.b')
| -rw-r--r-- | appl/cmd/import.b | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/appl/cmd/import.b b/appl/cmd/import.b new file mode 100644 index 00000000..657deb38 --- /dev/null +++ b/appl/cmd/import.b @@ -0,0 +1,192 @@ +implement Import; + +include "sys.m"; + sys: Sys; + +include "draw.m"; +include "keyring.m"; +include "security.m"; +include "factotum.m"; +include "encoding.m"; +include "arg.m"; + +Import: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +factotumfile := "/mnt/factotum/rpc"; + +fail(status, msg: string) +{ + sys->fprint(sys->fildes(2), "import: %s\n", msg); + raise "fail:"+status; +} + +nomod(mod: string) +{ + fail("load", sys->sprint("can't load %s: %r", mod)); +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + factotum := load Factotum Factotum->PATH; + if(factotum == nil) + nomod(Factotum->PATH); + factotum->init(); + + arg := load Arg Arg->PATH; + if(arg == nil) + nomod(Arg->PATH); + + arg->init(args); + arg->setusage("import [-a|-b] [-c] [-e enc digest] host file [localfile]"); + flags := 0; + cryptalg := ""; # will be rc4_256 sha1 + keyspec := ""; + while((o := arg->opt()) != 0) + case o { + 'a' => + flags |= Sys->MAFTER; + 'b' => + flags |= Sys->MBEFORE; + 'c' => + flags |= Sys->MCREATE; + 'e' => + cryptalg = arg->earg(); + if(cryptalg == "clear") + cryptalg = nil; + 'k' => + keyspec = arg->earg(); + '9' => + ; + * => + arg->usage(); + } + args = arg->argv(); + if(len args != 2 && len args != 3) + arg->usage(); + arg = nil; + addr := hd args; + file := hd tl args; + mountpt := file; + if(len args > 2) + mountpt = hd tl tl args; + + sys->pctl(Sys->FORKFD, nil); + + facfd := sys->open(factotumfile, Sys->ORDWR); + if(facfd == nil) + fail("factotum", sys->sprint("can't open %s: %r", factotumfile)); + + dest := netmkaddr(addr, "net", "exportfs"); + (ok, c) := sys->dial(dest, nil); + if(ok < 0) + fail("dial failed", sys->sprint("can't dial %s: %r", dest)); + ai := factotum->proxy(c.dfd, facfd, "proto=p9any role=client "+keyspec); + if(ai == nil) + fail("auth", sys->sprint("can't authenticate import: %r")); + if(sys->fprint(c.dfd, "%s", file) < 0) + fail("import", sys->sprint("can't write to remote: %r")); + buf := array[256] of byte; + if((n := sys->read(c.dfd, buf, len buf)) != 2 || buf[0] != byte 'O' || buf[1] != byte 'K'){ + if(n >= 4) + sys->werrstr("bad remote tree: "+string buf[0:n]); + fail("import", sys->sprint("import %s %s: %r", addr, file)); + } + if(cryptalg != nil){ + if(ai.secret == nil) + fail("import", "factotum didn't establish shared secret"); + random := load Random Random->PATH; + if(random == nil) + nomod(Random->PATH); + kr := load Keyring Keyring->PATH; + if(kr == nil) + nomod(Keyring->PATH); + base64 := load Encoding Encoding->BASE64PATH; + if(base64 == nil) + nomod(Encoding->BASE64PATH); + if(sys->fprint(c.dfd, "impo nofilter ssl\n") < 0) + fail("import", sys->sprint("can't write to remote: %r")); + key := array[16] of byte; # myrand[4] secret[8] hisrand[4] + key[0:] = random->randombuf(Random->ReallyRandom, 4); + ns := len ai.secret; + if(ns > 8) + ns = 8; + key[4:] = ai.secret[0:ns]; + if(sys->write(c.dfd, key, 4) != 4) + fail("import", sys->sprint("can't write key to remote: %r")); + if(readn(c.dfd, key[12:], 4) != 4) + fail("import", sys->sprint("can't read remote key: %r")); + digest := array[Keyring->SHA1dlen] of byte; + kr->sha1(key, len key, digest, nil); + err: string; + (c.dfd, err) = pushssl(c.dfd, base64->dec(S(digest[0:10])), base64->dec(S(digest[10:20])), cryptalg); + if(err != nil) + fail("import", sys->sprint("can't push security layer: %s", err)); + }else + if(sys->fprint(c.dfd, "impo nofilter clear\n") < 0) + fail("import", sys->sprint("can't write to remote: %r")); + afd := sys->fauth(c.dfd, ""); + if(afd != nil) + factotum->proxy(afd, facfd, "proto=p9any role=client"); + if(sys->mount(c.dfd, afd, mountpt, flags, "") < 0) + fail("mount failed", sys->sprint("import %s %s: mount failed: %r", addr, file)); +} + +readn(fd: ref Sys->FD, buf: array of byte, nb: int): int +{ + for(nr := 0; nr < nb;){ + n := sys->read(fd, buf[nr:], nb-nr); + if(n <= 0){ + if(nr == 0) + return n; + break; + } + nr += n; + } + return nr; +} + +S(a: array of byte): string +{ + s := ""; + for(i:=0; i<len a; i++) + s += sys->sprint("%.2ux", int a[i]); + return s; +} + +pushssl(fd: ref Sys->FD, secretin, secretout: array of byte, alg: string): (ref Sys->FD, string) +{ + ssl := load SSL SSL->PATH; + if(ssl == nil) + nomod(SSL->PATH); + + (err, c) := ssl->connect(fd); + if(err != nil) + return (nil, "can't connect ssl: " + err); + + err = ssl->secret(c, secretin, secretout); + if(err != nil) + return (nil, "can't write secret: " + err); + if(sys->fprint(c.cfd, "alg %s", alg) < 0) + return (nil, sys->sprint("can't push algorithm %s: %r", alg)); + + return (c.dfd, nil); +} + +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); +} |
