xref: /plan9/sys/src/cmd/import.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <libsec.h>
5 
6 enum {
7 	Encnone,
8 	Encssl,
9 	Enctls,
10 };
11 
12 static char *encprotos[] = {
13 	[Encnone] =	"clear",
14 	[Encssl] =		"ssl",
15 	[Enctls] = 		"tls",
16 				nil,
17 };
18 
19 char		*keyspec = "";
20 char		*filterp;
21 char		*ealgs = "rc4_256 sha1";
22 int		encproto = Encnone;
23 char		*aan = "/bin/aan";
24 AuthInfo 	*ai;
25 int		debug;
26 int		doauth = 1;
27 
28 int	connect(char*, char*, int);
29 int	passive(void);
30 int	old9p(int);
31 void	catcher(void*, char*);
32 void	sysfatal(char*, ...);
33 void	usage(void);
34 int	filter(int, char *, char *);
35 
36 static void	mksecret(char *, uchar *);
37 
38 void
39 post(char *name, char *envname, int srvfd)
40 {
41 	int fd;
42 	char buf[32];
43 
44 	fd = create(name, OWRITE, 0600);
45 	if(fd < 0)
46 		return;
47 	sprint(buf, "%d",srvfd);
48 	if(write(fd, buf, strlen(buf)) != strlen(buf))
49 		sysfatal("srv write: %r");
50 	close(fd);
51 	putenv(envname, name);
52 }
53 
54 static int
55 lookup(char *s, char *l[])
56 {
57 	int i;
58 
59 	for (i = 0; l[i] != 0; i++)
60 		if (strcmp(l[i], s) == 0)
61 			return i;
62 	return -1;
63 }
64 
65 void
66 main(int argc, char **argv)
67 {
68 	char *mntpt;
69 	int fd, mntflags;
70 	int oldserver;
71 	char *srvpost, srvfile[64];
72 	int backwards = 0;
73 
74 	srvpost = nil;
75 	oldserver = 0;
76 	mntflags = MREPL;
77 	ARGBEGIN{
78 	case 'A':
79 		doauth = 0;
80 		break;
81 	case 'a':
82 		mntflags = MAFTER;
83 		break;
84 	case 'b':
85 		mntflags = MBEFORE;
86 		break;
87 	case 'c':
88 		mntflags |= MCREATE;
89 		break;
90 	case 'C':
91 		mntflags |= MCACHE;
92 		break;
93 	case 'd':
94 		debug++;
95 		break;
96 	case 'f':
97 		/* ignored but allowed for compatibility */
98 		break;
99 	case 'O':
100 	case 'o':
101 		oldserver = 1;
102 		break;
103 	case 'E':
104 		if ((encproto = lookup(EARGF(usage()), encprotos)) < 0)
105 			usage();
106 		break;
107 	case 'e':
108 		ealgs = EARGF(usage());
109 		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
110 			ealgs = nil;
111 		break;
112 	case 'k':
113 		keyspec = EARGF(usage());
114 		break;
115 	case 'p':
116 		filterp = aan;
117 		break;
118 	case 's':
119 		srvpost = EARGF(usage());
120 		break;
121 	case 'B':
122 		backwards = 1;
123 		break;
124 	default:
125 		usage();
126 	}ARGEND;
127 
128 	mntpt = 0;		/* to shut up compiler */
129 	if(backwards){
130 		switch(argc) {
131 		default:
132 			mntpt = argv[0];
133 			break;
134 		case 0:
135 			usage();
136 		}
137 	} else {
138 		switch(argc) {
139 		case 2:
140 			mntpt = argv[1];
141 			break;
142 		case 3:
143 			mntpt = argv[2];
144 			break;
145 		default:
146 			usage();
147 		}
148 	}
149 
150 	if (encproto == Enctls)
151 		sysfatal("%s: tls has not yet been implemented\n", argv[0]);
152 
153 	notify(catcher);
154 	alarm(60*1000);
155 
156 	if(backwards)
157 		fd = passive();
158 	else
159 		fd = connect(argv[0], argv[1], oldserver);
160 
161 	if (!oldserver)
162 		fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter", encprotos[encproto]);
163 
164 	if (encproto != Encnone && ealgs && ai) {
165 		uchar key[16];
166 		uchar digest[SHA1dlen];
167 		char fromclientsecret[21];
168 		char fromserversecret[21];
169 		int i;
170 
171 		memmove(key+4, ai->secret, ai->nsecret);
172 
173 		/* exchange random numbers */
174 		srand(truerand());
175 		for(i = 0; i < 4; i++)
176 			key[i] = rand();
177 		if(write(fd, key, 4) != 4)
178 			sysfatal("can't write key part: %r");
179 		if(readn(fd, key+12, 4) != 4)
180 			sysfatal("can't read key part: %r");
181 
182 		/* scramble into two secrets */
183 		sha1(key, sizeof(key), digest, nil);
184 		mksecret(fromclientsecret, digest);
185 		mksecret(fromserversecret, digest+10);
186 
187 		if (filterp)
188 			fd = filter(fd, filterp, argv[0]);
189 
190 		/* set up encryption */
191 		fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
192 		if(fd < 0)
193 			sysfatal("can't establish ssl connection: %r");
194 	}
195 	else if (filterp)
196 		fd = filter(fd, filterp, argv[0]);
197 
198 	if(srvpost){
199 		sprint(srvfile, "/srv/%s", srvpost);
200 		remove(srvfile);
201 		post(srvfile, srvpost, fd);
202 	}
203 	if(mount(fd, -1, mntpt, mntflags, "") < 0)
204 		sysfatal("can't mount %s: %r", argv[1]);
205 	alarm(0);
206 
207 	if(backwards && argc > 1){
208 		exec(argv[1], &argv[1]);
209 		sysfatal("exec: %r");
210 	}
211 	exits(0);
212 }
213 
214 void
215 catcher(void*, char *msg)
216 {
217 	if(strcmp(msg, "alarm") == 0)
218 		noted(NCONT);
219 	noted(NDFLT);
220 }
221 
222 int
223 old9p(int fd)
224 {
225 	int p[2];
226 
227 	if(pipe(p) < 0)
228 		sysfatal("pipe: %r");
229 
230 	switch(rfork(RFPROC|RFFDG|RFNAMEG)) {
231 	case -1:
232 		sysfatal("rfork srvold9p: %r");
233 	case 0:
234 		if(fd != 1){
235 			dup(fd, 1);
236 			close(fd);
237 		}
238 		if(p[0] != 0){
239 			dup(p[0], 0);
240 			close(p[0]);
241 		}
242 		close(p[1]);
243 		if(0){
244 			fd = open("/sys/log/cpu", OWRITE);
245 			if(fd != 2){
246 				dup(fd, 2);
247 				close(fd);
248 			}
249 			execl("/bin/srvold9p", "srvold9p", "-ds", nil);
250 		} else
251 			execl("/bin/srvold9p", "srvold9p", "-s", nil);
252 		sysfatal("exec srvold9p: %r");
253 	default:
254 		close(fd);
255 		close(p[0]);
256 	}
257 	return p[1];
258 }
259 
260 int
261 connect(char *system, char *tree, int oldserver)
262 {
263 	char buf[ERRMAX], dir[128], *na;
264 	int fd, n;
265 	char *authp;
266 
267 	na = netmkaddr(system, 0, "exportfs");
268 	if((fd = dial(na, 0, dir, 0)) < 0)
269 		sysfatal("can't dial %s: %r", system);
270 
271 	if(doauth){
272 		if(oldserver)
273 			authp = "p9sk2";
274 		else
275 			authp = "p9any";
276 
277 		ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", authp, keyspec);
278 		if(ai == nil)
279 			sysfatal("%r: %s", system);
280 	}
281 
282 	n = write(fd, tree, strlen(tree));
283 	if(n < 0)
284 		sysfatal("can't write tree: %r");
285 
286 	strcpy(buf, "can't read tree");
287 
288 	n = read(fd, buf, sizeof buf - 1);
289 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
290 		buf[sizeof buf - 1] = '\0';
291 		sysfatal("bad remote tree: %s", buf);
292 	}
293 
294 	if(oldserver)
295 		return old9p(fd);
296 	return fd;
297 }
298 
299 int
300 passive(void)
301 {
302 	int fd;
303 
304 	/*
305 	 * Ignore doauth==0 on purpose.  Is it useful here?
306 	 */
307 
308 	ai = auth_proxy(0, auth_getkey, "proto=p9any role=server");
309 	if(ai == nil)
310 		sysfatal("auth_proxy: %r");
311 	if(auth_chuid(ai, nil) < 0)
312 		sysfatal("auth_chuid: %r");
313 	putenv("service", "import");
314 
315 	fd = dup(0, -1);
316 	close(0);
317 	open("/dev/null", ORDWR);
318 	close(1);
319 	open("/dev/null", ORDWR);
320 
321 	return fd;
322 }
323 
324 void
325 usage(void)
326 {
327 	fprint(2, "usage: import [-abcC] [-A] [-E clear|ssl|tls] [-e 'crypt auth'|clear] [-k keypattern] [-p] host remotefs [mountpoint]\n");
328 	exits("usage");
329 }
330 
331 /* Network on fd1, mount driver on fd0 */
332 int
333 filter(int fd, char *cmd, char *host)
334 {
335 	int p[2], len, argc;
336 	char newport[256], buf[256], *s;
337 	char *argv[16], *file, *pbuf;
338 
339 	if ((len = read(fd, newport, sizeof newport - 1)) < 0)
340 		sysfatal("filter: cannot write port; %r\n");
341 	newport[len] = '\0';
342 
343 	if ((s = strchr(newport, '!')) == nil)
344 		sysfatal("filter: illegally formatted port %s\n", newport);
345 
346 	strecpy(buf, buf+sizeof buf, netmkaddr(host, "tcp", "0"));
347 	pbuf = strrchr(buf, '!');
348 	strecpy(pbuf, buf+sizeof buf, s);
349 
350 	if(debug)
351 		fprint(2, "filter: remote port %s\n", newport);
352 
353 	argc = tokenize(cmd, argv, nelem(argv)-2);
354 	if (argc == 0)
355 		sysfatal("filter: empty command");
356 	argv[argc++] = "-c";
357 	argv[argc++] = buf;
358 	argv[argc] = nil;
359 	file = argv[0];
360 	if (s = strrchr(argv[0], '/'))
361 		argv[0] = s+1;
362 
363 	if(pipe(p) < 0)
364 		sysfatal("pipe: %r");
365 
366 	switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
367 	case -1:
368 		sysfatal("rfork record module: %r");
369 	case 0:
370 		dup(p[0], 1);
371 		dup(p[0], 0);
372 		close(p[0]);
373 		close(p[1]);
374 		exec(file, argv);
375 		sysfatal("exec record module: %r");
376 	default:
377 		close(fd);
378 		close(p[0]);
379 	}
380 	return p[1];
381 }
382 
383 static void
384 mksecret(char *t, uchar *f)
385 {
386 	sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
387 		f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
388 }
389