The code is adapted from Plan 9's import(4); this allows us to speak that protocol. We don't currently support AAN (in the works) or TLS/SSL. Thanks to David for help with the man page, testing, and development. R=0intro, rsc CC=plan9port.codebot http://codereview.appspot.com/6458100
239 lines
4.3 KiB
C
239 lines
4.3 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <auth.h>
|
|
#include <thread.h>
|
|
|
|
enum {
|
|
Encnone,
|
|
Encssl,
|
|
Enctls,
|
|
};
|
|
|
|
static char *encprotos[] = {
|
|
[Encnone] = "clear",
|
|
[Encssl] = "ssl",
|
|
[Enctls] = "tls",
|
|
nil,
|
|
};
|
|
|
|
char *keyspec = "";
|
|
char *filterp;
|
|
char *ealgs = "rc4_256 sha1";
|
|
int encproto = Encnone;
|
|
AuthInfo *ai;
|
|
int debug;
|
|
int doauth = 1;
|
|
int timedout;
|
|
|
|
int connectez(char*, char*);
|
|
void sysfatal(char*, ...);
|
|
void usage(void);
|
|
int filter(int, char *, char *);
|
|
|
|
int
|
|
catcher(void *v, char *msg)
|
|
{
|
|
timedout = 1;
|
|
if(strcmp(msg, "alarm") == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
lookup(char *s, char *l[])
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; l[i] != 0; i++)
|
|
if (strcmp(l[i], s) == 0)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
static char*
|
|
srvname(char *addr)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i<strlen(addr); i++){
|
|
if(addr[i] == '!')
|
|
addr[i] = ':';
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
void
|
|
threadmain(int argc, char **argv)
|
|
{
|
|
char *mntpt, *srvpost, srvfile[64];
|
|
int fd;
|
|
|
|
quotefmtinstall();
|
|
srvpost = nil;
|
|
ARGBEGIN{
|
|
case 'A':
|
|
doauth = 0;
|
|
break;
|
|
case 'd':
|
|
debug++;
|
|
break;
|
|
case 'E':
|
|
if ((encproto = lookup(EARGF(usage()), encprotos)) < 0)
|
|
usage();
|
|
break;
|
|
case 'e':
|
|
ealgs = EARGF(usage());
|
|
if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
|
|
ealgs = nil;
|
|
break;
|
|
case 'k':
|
|
keyspec = EARGF(usage());
|
|
break;
|
|
case 'p':
|
|
filterp = unsharp("#9/bin/aan");
|
|
break;
|
|
case 's':
|
|
srvpost = EARGF(usage());
|
|
break;
|
|
default:
|
|
usage();
|
|
}ARGEND;
|
|
|
|
mntpt = 0; /* to shut up compiler */
|
|
switch(argc) {
|
|
case 2:
|
|
mntpt = argv[1];
|
|
break;
|
|
case 3:
|
|
mntpt = argv[2];
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
if(encproto != Encnone)
|
|
sysfatal("%s: tls and ssl have not yet been implemented", argv[0]);
|
|
|
|
threadnotify(catcher, 1);
|
|
alarm(60*1000);
|
|
|
|
fd = connectez(argv[0], argv[1]);
|
|
|
|
fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter",
|
|
encprotos[encproto]);
|
|
|
|
if (filterp)
|
|
fd = filter(fd, filterp, argv[0]);
|
|
|
|
if(srvpost == nil)
|
|
srvpost = srvname(argv[0]);
|
|
sprint(srvfile, "%s", srvpost);
|
|
|
|
if(post9pservice(fd, srvfile, mntpt) < 0)
|
|
sysfatal("can't post %s: %r", argv[1]);
|
|
alarm(0);
|
|
|
|
threadexitsall(0);
|
|
}
|
|
|
|
/* the name "connect" is special */
|
|
int
|
|
connectez(char *system, char *tree)
|
|
{
|
|
char buf[ERRMAX], *na;
|
|
int fd, n;
|
|
char *authp;
|
|
|
|
na = netmkaddr(system, "tcp", "exportfs");
|
|
threadsetname("dial %s", na);
|
|
if((fd = dial(na, nil, nil, nil)) < 0)
|
|
sysfatal("can't dial %s: %r", system);
|
|
|
|
if(doauth){
|
|
authp = "p9any";
|
|
threadsetname("auth_proxy auth_getkey proto=%q role=client %s",
|
|
authp, keyspec);
|
|
ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s",
|
|
authp, keyspec);
|
|
if(ai == nil)
|
|
sysfatal("%r: %s", system);
|
|
}
|
|
|
|
threadsetname("writing tree name %s", tree);
|
|
n = write(fd, tree, strlen(tree));
|
|
if(n < 0)
|
|
sysfatal("can't write tree: %r");
|
|
|
|
strcpy(buf, "can't read tree");
|
|
|
|
threadsetname("awaiting OK for %s", tree);
|
|
n = read(fd, buf, sizeof buf - 1);
|
|
if(n!=2 || buf[0]!='O' || buf[1]!='K'){
|
|
if (timedout)
|
|
sysfatal("timed out connecting to %s", na);
|
|
buf[sizeof buf - 1] = '\0';
|
|
sysfatal("bad remote tree: %s", buf);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: 9import [-A] [-E clear|ssl|tls] "
|
|
"[-e 'crypt auth'|clear] [-k keypattern] [-p] [-s srv] host remotefs [mountpoint]\n");
|
|
threadexitsall("usage");
|
|
}
|
|
|
|
/* Network on fd1, mount driver on fd0 */
|
|
int
|
|
filter(int fd, char *cmd, char *host)
|
|
{
|
|
int p[2], len, argc;
|
|
char newport[256], buf[256], *s;
|
|
char *argv[16], *file, *pbuf;
|
|
|
|
if ((len = read(fd, newport, sizeof newport - 1)) < 0)
|
|
sysfatal("filter: cannot write port; %r");
|
|
newport[len] = '\0';
|
|
|
|
if ((s = strchr(newport, '!')) == nil)
|
|
sysfatal("filter: illegally formatted port %s", newport);
|
|
|
|
strecpy(buf, buf+sizeof buf, netmkaddr(host, "tcp", "0"));
|
|
pbuf = strrchr(buf, '!');
|
|
strecpy(pbuf, buf+sizeof buf, s);
|
|
|
|
if(debug)
|
|
fprint(2, "filter: remote port %s\n", newport);
|
|
|
|
argc = tokenize(cmd, argv, nelem(argv)-2);
|
|
if (argc == 0)
|
|
sysfatal("filter: empty command");
|
|
argv[argc++] = "-c";
|
|
argv[argc++] = buf;
|
|
argv[argc] = nil;
|
|
file = argv[0];
|
|
if (s = strrchr(argv[0], '/'))
|
|
argv[0] = s+1;
|
|
|
|
if(pipe(p) < 0)
|
|
sysfatal("pipe: %r");
|
|
|
|
switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
|
|
case -1:
|
|
sysfatal("rfork record module: %r");
|
|
case 0:
|
|
dup(p[0], 1);
|
|
dup(p[0], 0);
|
|
close(p[0]);
|
|
close(p[1]);
|
|
exec(file, argv);
|
|
sysfatal("exec record module: %r");
|
|
default:
|
|
close(fd);
|
|
close(p[0]);
|
|
}
|
|
return p[1];
|
|
}
|