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