1implement Import; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7include "dial.m"; 8include "keyring.m"; 9include "security.m"; 10include "factotum.m"; 11include "encoding.m"; 12include "arg.m"; 13 14Import: module 15{ 16 init: fn(nil: ref Draw->Context, nil: list of string); 17}; 18 19factotumfile := "/mnt/factotum/rpc"; 20 21fail(status, msg: string) 22{ 23 sys->fprint(sys->fildes(2), "import: %s\n", msg); 24 raise "fail:"+status; 25} 26 27nomod(mod: string) 28{ 29 fail("load", sys->sprint("can't load %s: %r", mod)); 30} 31 32init(nil: ref Draw->Context, args: list of string) 33{ 34 sys = load Sys Sys->PATH; 35 factotum := load Factotum Factotum->PATH; 36 if(factotum == nil) 37 nomod(Factotum->PATH); 38 factotum->init(); 39 dial := load Dial Dial->PATH; 40 41 arg := load Arg Arg->PATH; 42 if(arg == nil) 43 nomod(Arg->PATH); 44 45 arg->init(args); 46 arg->setusage("import [-a|-b] [-c] [-e enc digest] host file [localfile]"); 47 flags := 0; 48 cryptalg := ""; # will be rc4_256 sha1 49 keyspec := ""; 50 while((o := arg->opt()) != 0) 51 case o { 52 'a' => 53 flags |= Sys->MAFTER; 54 'b' => 55 flags |= Sys->MBEFORE; 56 'c' => 57 flags |= Sys->MCREATE; 58 'e' => 59 cryptalg = arg->earg(); 60 if(cryptalg == "clear") 61 cryptalg = nil; 62 'k' => 63 keyspec = arg->earg(); 64 '9' => 65 ; 66 * => 67 arg->usage(); 68 } 69 args = arg->argv(); 70 if(len args != 2 && len args != 3) 71 arg->usage(); 72 arg = nil; 73 addr := hd args; 74 file := hd tl args; 75 mountpt := file; 76 if(len args > 2) 77 mountpt = hd tl tl args; 78 79 sys->pctl(Sys->FORKFD, nil); 80 81 facfd := sys->open(factotumfile, Sys->ORDWR); 82 if(facfd == nil) 83 fail("factotum", sys->sprint("can't open %s: %r", factotumfile)); 84 85 dest := dial->netmkaddr(addr, "net", "exportfs"); 86 c := dial->dial(dest, nil); 87 if(c == nil) 88 fail("dial failed", sys->sprint("can't dial %s: %r", dest)); 89 ai := factotum->proxy(c.dfd, facfd, "proto=p9any role=client "+keyspec); 90 if(ai == nil) 91 fail("auth", sys->sprint("can't authenticate import: %r")); 92 if(sys->fprint(c.dfd, "%s", file) < 0) 93 fail("import", sys->sprint("can't write to remote: %r")); 94 buf := array[256] of byte; 95 if((n := sys->read(c.dfd, buf, len buf)) != 2 || buf[0] != byte 'O' || buf[1] != byte 'K'){ 96 if(n >= 4) 97 sys->werrstr("bad remote tree: "+string buf[0:n]); 98 fail("import", sys->sprint("import %s %s: %r", addr, file)); 99 } 100 if(cryptalg != nil){ 101 if(ai.secret == nil) 102 fail("import", "factotum didn't establish shared secret"); 103 random := load Random Random->PATH; 104 if(random == nil) 105 nomod(Random->PATH); 106 kr := load Keyring Keyring->PATH; 107 if(kr == nil) 108 nomod(Keyring->PATH); 109 base64 := load Encoding Encoding->BASE64PATH; 110 if(base64 == nil) 111 nomod(Encoding->BASE64PATH); 112 if(sys->fprint(c.dfd, "impo nofilter ssl\n") < 0) 113 fail("import", sys->sprint("can't write to remote: %r")); 114 key := array[16] of byte; # myrand[4] secret[8] hisrand[4] 115 key[0:] = random->randombuf(Random->ReallyRandom, 4); 116 ns := len ai.secret; 117 if(ns > 8) 118 ns = 8; 119 key[4:] = ai.secret[0:ns]; 120 if(sys->write(c.dfd, key, 4) != 4) 121 fail("import", sys->sprint("can't write key to remote: %r")); 122 if(sys->readn(c.dfd, key[12:], 4) != 4) 123 fail("import", sys->sprint("can't read remote key: %r")); 124 digest := array[Keyring->SHA1dlen] of byte; 125 kr->sha1(key, len key, digest, nil); 126 err: string; 127 (c.dfd, err) = pushssl(c.dfd, base64->dec(S(digest[0:10])), base64->dec(S(digest[10:20])), cryptalg); 128 if(err != nil) 129 fail("import", sys->sprint("can't push security layer: %s", err)); 130 }else 131 if(sys->fprint(c.dfd, "impo nofilter clear\n") < 0) 132 fail("import", sys->sprint("can't write to remote: %r")); 133 afd := sys->fauth(c.dfd, ""); 134 if(afd != nil) 135 factotum->proxy(afd, facfd, "proto=p9any role=client"); 136 if(sys->mount(c.dfd, afd, mountpt, flags, "") < 0) 137 fail("mount failed", sys->sprint("import %s %s: mount failed: %r", addr, file)); 138} 139 140S(a: array of byte): string 141{ 142 s := ""; 143 for(i:=0; i<len a; i++) 144 s += sys->sprint("%.2ux", int a[i]); 145 return s; 146} 147 148pushssl(fd: ref Sys->FD, secretin, secretout: array of byte, alg: string): (ref Sys->FD, string) 149{ 150 ssl := load SSL SSL->PATH; 151 if(ssl == nil) 152 nomod(SSL->PATH); 153 154 (err, c) := ssl->connect(fd); 155 if(err != nil) 156 return (nil, "can't connect ssl: " + err); 157 158 err = ssl->secret(c, secretin, secretout); 159 if(err != nil) 160 return (nil, "can't write secret: " + err); 161 if(sys->fprint(c.cfd, "alg %s", alg) < 0) 162 return (nil, sys->sprint("can't push algorithm %s: %r", alg)); 163 164 return (c.dfd, nil); 165} 166