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