1implement P9export; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7include "keyring.m"; 8include "security.m"; 9include "factotum.m"; 10include "encoding.m"; 11include "arg.m"; 12 13P9export: module 14{ 15 init: fn(nil: ref Draw->Context, nil: list of string); 16}; 17 18factotumfile := "/mnt/factotum/rpc"; 19 20fail(status, msg: string) 21{ 22 sys->fprint(sys->fildes(2), "9export: %s\n", msg); 23 raise "fail:"+status; 24} 25 26nomod(mod: string) 27{ 28 fail("load", sys->sprint("can't load %s: %r", mod)); 29} 30 31init(nil: ref Draw->Context, args: list of string) 32{ 33 sys = load Sys Sys->PATH; 34 35 arg := load Arg Arg->PATH; 36 if(arg == nil) 37 nomod(Arg->PATH); 38 39 arg->init(args); 40 arg->setusage("9export [-aA9] [-k keyspec] [-e enc digest]"); 41 cryptalg := ""; # will be rc4_256 sha1 42 keyspec := ""; 43 noauth := 0; 44 xflag := Sys->EXPWAIT; 45 while((o := arg->opt()) != 0) 46 case o { 47 'a' => 48 xflag = Sys->EXPASYNC; 49 'A' => 50 noauth = 1; 51 'e' => 52 cryptalg = arg->earg(); 53 if(cryptalg == "clear") 54 cryptalg = nil; 55 'k' => 56 keyspec = arg->earg(); 57 '9' => 58 ; 59 * => 60 arg->usage(); 61 } 62 args = arg->argv(); 63 arg = nil; 64 65 sys->pctl(Sys->FORKFD|Sys->FORKNS, nil); 66 67 fd := sys->fildes(0); 68 69 secret: array of byte; 70 if(noauth == 0){ 71 factotum := load Factotum Factotum->PATH; 72 if(factotum == nil) 73 nomod(Factotum->PATH); 74 factotum->init(); 75 facfd := sys->open(factotumfile, Sys->ORDWR); 76 if(facfd == nil) 77 fail("factotum", sys->sprint("can't open %s: %r", factotumfile)); 78 ai := factotum->proxy(fd, facfd, "proto=p9any role=server "+keyspec); 79 if(ai == nil) 80 fail("auth", sys->sprint("can't authenticate 9export: %r")); 81 secret = ai.secret; 82 } 83 84 # read tree; it's a Plan 9 bug that there's no reliable delimiter 85 btree := array[2048] of byte; 86 n := sys->read(fd, btree, len btree); 87 if(n <= 0) 88 fail("tree", sys->sprint("can't read tree: %r")); 89 tree := string btree[0:n]; 90 if(sys->chdir(tree) < 0){ 91 sys->fprint(fd, "chdir(%d:\"%s\"): %r", n, tree); 92 fail("tree", sys->sprint("bad tree: %s", tree)); 93 } 94 if(sys->write(fd, array of byte "OK", 2) != 2) 95 fail("tree", sys->sprint("can't OK tree: %r")); 96 impo := array[2048] of byte; 97 for(n = 0; n < len impo; n++) 98 if(sys->read(fd, impo[n:], 1) != 1) 99 fail("impo", sys->sprint("can't read impo: %r")); 100 else if(impo[n] == byte 0 || impo[n] == byte '\n') 101 break; 102 if(n < 4 || string impo[0:4] != "impo") 103 fail("impo", "wasn't impo: possibly old import/cpu"); 104 if(noauth == 0 && cryptalg != nil){ 105 if(secret == nil) 106 fail("import", "didn't establish shared secret"); 107 random := load Random Random->PATH; 108 if(random == nil) 109 nomod(Random->PATH); 110 kr := load Keyring Keyring->PATH; 111 if(kr == nil) 112 nomod(Keyring->PATH); 113 ssl := load SSL SSL->PATH; 114 if(ssl == nil) 115 nomod(SSL->PATH); 116 base64 := load Encoding Encoding->BASE64PATH; 117 if(base64 == nil) 118 nomod(Encoding->BASE64PATH); 119 key := array[16] of byte; # myrand[4] secret[8] hisrand[4] 120 key[0:] = random->randombuf(Random->ReallyRandom, 4); 121 ns := len secret; 122 if(ns > 8) 123 ns = 8; 124 key[12:] = secret[0:ns]; 125 if(sys->write(fd, key[12:], 4) != 4) 126 fail("import", sys->sprint("can't write key to remote: %r")); 127 if(sys->readn(fd, key, 4) != 4) 128 fail("import", sys->sprint("can't read remote key: %r")); 129 digest := array[Keyring->SHA1dlen] of byte; 130 kr->sha1(key, len key, digest, nil); 131 err: string; 132 (fd, err) = pushssl(fd, base64->dec(S(digest[10:20])), base64->dec(S(digest[0:10])), cryptalg); 133 if(err != nil) 134 fail("import", sys->sprint("can't push security layer: %s", err)); 135 } 136 if(sys->export(fd, ".", xflag) < 0) 137 fail("export", sys->sprint("can't export %s: %r", tree)); 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