Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
}