xref: /inferno-os/appl/cmd/import.b (revision 9274481003af38a88988b4e9a3a2c3e0df206bee)
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