xref: /inferno-os/appl/cmd/9export.b (revision a6011949be081a8fe1bec0713ce60c36beb3a351)
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