#include <u.h>
#include <libc.h>
-#include <bio.h>
#include <auth.h>
#include <fcall.h>
#include <libsec.h>
#define Maxfdata 8192
#define MaxStr 128
-void remoteside(int);
-void fatal(int, char*, ...);
+void remoteside(void);
+void fatal(char*, ...);
void lclnoteproc(int);
void rmtnoteproc(void);
void catcher(void*, char*);
int readstr(int, char*, int);
char *rexcall(int*, char*, char*);
int setamalg(char*);
-char *keyspec = "";
+char *keyspec = "";
int notechan;
int exportpid;
char *system;
int cflag;
+int nflag;
int dbg;
char *user;
char *patternfile;
/* message size for exportfs; may be larger so we can do big graphics in CPU window */
int msgsize = Maxfdata+IOHDRSZ;
+/* encryption mechanisms */
+static int clear(int);
+
+int (*encryption)(int) = clear;
+
/* authentication mechanisms */
static int netkeyauth(int);
static int netkeysrvauth(int, char*);
char *name; /* name of method */
int (*cf)(int); /* client side authentication */
int (*sf)(int, char*); /* server side authentication */
-} authmethod[] =
-{
+} authmethod[] = {
{ "p9", p9auth, srvp9auth,},
{ "netkey", netkeyauth, netkeysrvauth,},
-// { "none", noauth, srvnoauth,},
+ { "none", noauth, srvnoauth,},
{ nil, nil}
};
AuthMethod *am = authmethod; /* default is p9 */
-char *p9authproto = "p9any";
-
int setam(char*);
+char *aan = "/bin/aan";
+char *anstring = "tcp!*!0";
+char *filterp = nil;
+
+int filter(int fd, char *host);
+
void
usage(void)
{
- fprint(2, "usage: cpu [-h system] [-u user] [-a authmethod] "
+ fprint(2, "usage: cpu [-p] [-h system] [-u user] [-a authmethod] "
"[-e 'crypt hash'] [-k keypattern] [-P patternfile] "
"[-c cmd arg ...]\n");
exits("usage");
return strdup(lp+1);
}
-/*
- * based on libthread's threadsetname, but drags in less library code.
- * actually just sets the arguments displayed.
- */
-void
-procsetname(char *fmt, ...)
-{
- int fd;
- char *cmdname;
- char buf[128];
- va_list arg;
-
- va_start(arg, fmt);
- cmdname = vsmprint(fmt, arg);
- va_end(arg);
- if (cmdname == nil)
- return;
- snprint(buf, sizeof buf, "#p/%d/args", getpid());
- if((fd = open(buf, OWRITE)) >= 0){
- write(fd, cmdname, strlen(cmdname)+1);
- close(fd);
- }
- free(cmdname);
-}
-
void
main(int argc, char **argv)
{
- char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err;
+ char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *s, *err;
int ac, fd, ms, data;
char *av[10];
origargs = procgetname();
/* see if we should use a larger message size */
fd = open("/dev/draw", OREAD);
- if(fd > 0){
+ if(fd >= 0){
ms = iounit(fd);
if(msgsize < ms+IOHDRSZ)
msgsize = ms+IOHDRSZ;
user = getuser();
if(user == nil)
- fatal(1, "can't read user name");
+ fatal("can't read user name: %r");
ARGBEGIN{
case 'a':
p = EARGF(usage());
if(setam(p) < 0)
- fatal(0, "unknown auth method %s", p);
+ fatal("unknown auth method %s", p);
break;
case 'e':
ealgs = EARGF(usage());
case 'f':
/* ignored but accepted for compatibility */
break;
- case 'O':
- p9authproto = "p9sk2";
- remoteside(1); /* From listen */
+ case 'n':
+ /* must be specified before -R/-O */
+ nflag++;
+ break;
+ case 'A':
+ anstring = EARGF(usage());
break;
case 'R': /* From listen */
- remoteside(0);
+ remoteside();
break;
case 'h':
system = EARGF(usage());
break;
case 'c':
cflag++;
- cmd[0] = '!';
- cmd[1] = '\0';
- while(p = ARGF()) {
- strcat(cmd, " ");
- strcat(cmd, p);
- }
+ s = cmd;
+ *s++ = '!';
+ *s = 0;
+ while(p = ARGF())
+ s = seprint(s, cmd+sizeof(cmd), " %q", p);
break;
case 'k':
keyspec = smprint("%s %s", keyspec, EARGF(usage()));
user = EARGF(usage());
keyspec = smprint("%s user=%s", keyspec, user);
break;
+ case 'p':
+ filterp = aan;
+ break;
default:
usage();
}ARGEND;
if(system == nil) {
p = getenv("cpu");
if(p == 0)
- fatal(0, "set $cpu");
+ fatal("set $cpu");
system = p;
}
if(err = rexcall(&data, system, srvname))
- fatal(1, "%s: %s", err, system);
+ fatal("%s: %s: %r", err, system);
procsetname("%s", origargs);
/* Tell the remote side the command to execute and where our working directory is */
* of /mnt/term
*/
if(readstr(data, buf, sizeof(buf)) < 0)
- fatal(1, "waiting for FS: %r");
+ fatal("waiting for FS: %r");
if(strncmp("FS", buf, 2) != 0) {
print("remote cpu: %s", buf);
exits(buf);
}
av[ac] = nil;
exec(exportfs, av);
- fatal(1, "starting exportfs");
+ fatal("starting exportfs: %r");
}
void
-fatal(int syserr, char *fmt, ...)
+fatal(char *fmt, ...)
{
- Fmt f;
- char *str;
+ char buf[1024];
va_list arg;
- fmtstrinit(&f);
- fmtprint(&f, "cpu: ");
va_start(arg, fmt);
- fmtvprint(&f, fmt, arg);
+ vsnprint(buf, sizeof(buf), fmt, arg);
va_end(arg);
- if(syserr)
- fmtprint(&f, ": %r");
- str = fmtstrflush(&f);
-
- fprint(2, "%s\n", str);
- syslog(0, "cpu", str);
- exits(str);
+ fprint(2, "cpu: %s\n", buf);
+ syslog(0, "cpu", "%s", buf);
+ exits(buf);
}
char *negstr = "negotiating authentication method";
-char bug[256];
-
-int
-old9p(int fd)
-{
- int p[2];
-
- if(pipe(p) < 0)
- fatal(1, "pipe");
-
- switch(rfork(RFPROC|RFFDG|RFNAMEG)) {
- case -1:
- fatal(1, "rfork srvold9p");
- case 0:
- if(fd != 1){
- dup(fd, 1);
- close(fd);
- }
- if(p[0] != 0){
- dup(p[0], 0);
- close(p[0]);
- }
- close(p[1]);
- if(0){
- fd = open("/sys/log/cpu", OWRITE);
- if(fd != 2){
- dup(fd, 2);
- close(fd);
- }
- execl("/bin/srvold9p", "srvold9p", "-ds", nil);
- } else
- execl("/bin/srvold9p", "srvold9p", "-s", nil);
- fatal(1, "exec srvold9p");
- default:
- close(fd);
- close(p[0]);
- }
- return p[1];
-}
-
-/* Invoked with stdin, stdout and stderr connected to the network connection */
+/* Invoked with stdin and stdout connected to the network connection */
void
-remoteside(int old)
+remoteside(void)
{
- char user[MaxStr], home[MaxStr], buf[MaxStr], xdir[MaxStr], cmd[MaxStr];
+ char user[MaxStr], buf[MaxStr], xdir[MaxStr], cmd[MaxStr];
int i, n, fd, badchdir, gotcmd;
rfork(RFENVG);
/* negotiate authentication mechanism */
n = readstr(fd, cmd, sizeof(cmd));
if(n < 0)
- fatal(1, "authenticating");
- if(setamalg(cmd) < 0){
+ fatal("authenticating: %r");
+ filterp = nil;
+ if(strcmp(cmd, "aan") == 0){
+ filterp = aan;
+ writestr(fd, "", nil, 1);
+ n = readstr(fd, cmd, sizeof(cmd));
+ if(n < 0)
+ fatal("authenticating: %r");
+ }
+ if(setamalg(cmd) < 0 || (nflag == 0 && am->sf == srvnoauth)) {
writestr(fd, "unsupported auth method", nil, 0);
- fatal(1, "bad auth method %s", cmd);
+ fatal("bad auth method %s", cmd);
} else
writestr(fd, "", "", 1);
- fd = (*am->sf)(fd, user);
- if(fd < 0)
- fatal(1, "srvauth");
-
- /* Set environment values for the user */
- putenv("user", user);
- sprint(home, "/usr/%s", user);
- putenv("home", home);
+ if((fd = (*am->sf)(fd, user)) < 0)
+ fatal("srvauth: %r");
+ if((fd = filter(fd, nil)) < 0)
+ fatal("filter: %r");
+ if((fd = encryption(fd)) < 0)
+ fatal("encrypt: %r");
/* Now collect invoking cpu's current directory or possibly a command */
gotcmd = 0;
if(readstr(fd, xdir, sizeof(xdir)) < 0)
- fatal(1, "dir/cmd");
+ fatal("dir/cmd: %r");
if(xdir[0] == '!') {
strcpy(cmd, &xdir[1]);
gotcmd = 1;
if(readstr(fd, xdir, sizeof(xdir)) < 0)
- fatal(1, "dir");
+ fatal("dir: %r");
}
- /* Establish the new process at the current working directory of the
- * gnot */
+ /* Establish the new process at the current working directory of the gnot */
badchdir = 0;
- if(strcmp(xdir, "NO") == 0)
- chdir(home);
- else if(chdir(xdir) < 0) {
- badchdir = 1;
- chdir(home);
- }
+ if(strcmp(xdir, "NO") != 0)
+ if(chdir(xdir) < 0)
+ badchdir = 1;
/* Start the gnot serving its namespace */
writestr(fd, "FS", "FS", 0);
if(n != 2 || buf[0] != 'O' || buf[1] != 'K')
exits("remote tree");
- if(old)
- fd = old9p(fd);
-
/* make sure buffers are big by doing fversion explicitly; pick a huge number; other side will trim */
strcpy(buf, VERSION9P);
if(fversion(fd, 64*1024, buf, sizeof buf) < 0)
execl("/bin/rc", "rc", "-lc", cmd, nil);
else
execl("/bin/rc", "rc", "-li", nil);
- fatal(1, "exec shell");
+ fatal("exec shell: %r");
}
char*
rexcall(int *fd, char *host, char *service)
{
char *na;
- char dir[MaxStr];
char err[ERRMAX];
char msg[MaxStr];
int n;
na = netmkaddr(host, 0, service);
procsetname("dialing %s", na);
- if((*fd = dial(na, 0, dir, 0)) < 0)
+ if((*fd = dial(na, 0, 0, 0)) < 0)
return "can't dial";
+ /* negotiate aan filter extension */
+ if(filterp == aan){
+ writestr(*fd, "aan", "negotiating aan", 0);
+ n = readstr(*fd, err, sizeof err);
+ if(n < 0)
+ return "negotiating aan";
+ if(*err){
+ errstr(err, sizeof err);
+ return negstr;
+ }
+ }
+
/* negotiate authentication mechanism */
if(ealgs != nil)
snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
if(n < 0)
return negstr;
if(*err){
- werrstr(err);
+ errstr(err, sizeof err);
return negstr;
}
/* authenticate */
procsetname("%s: auth via %s", origargs, am->name);
- *fd = (*am->cf)(*fd);
- if(*fd < 0)
+ if((*fd = (*am->cf)(*fd)) < 0)
return "can't authenticate";
- return 0;
+ if((*fd = filter(*fd, system)) < 0)
+ return "can't filter";
+ if((*fd = encryption(*fd)) < 0)
+ return "can't encrypt";
+ return nil;
}
void
l = strlen(str);
n = write(fd, str, l+1);
if(!ignore && n < 0)
- fatal(1, "writing network: %s", thing);
+ fatal("writing network: %s: %r", thing);
}
int
return p-buf;
}
+/*
+ * chown network connection
+ */
+static void
+setnetuser(int fd, char *user)
+{
+ Dir nd;
+ nulldir(&nd);
+ nd.mode = 0660;
+ nd.uid = user;
+ dirfwstat(fd, &nd);
+}
+
/*
* user level challenge/response
*/
int tries;
AuthInfo *ai;
- if(readstr(fd, user, 32) < 0)
+ if(readstr(fd, user, MaxStr) < 0)
return -1;
ai = nil;
return -1;
writestr(fd, "", "challenge", 1);
if(auth_chuid(ai, 0) < 0)
- fatal(1, "newns");
+ fatal("newns: %r");
+ setnetuser(fd, ai->cuid);
auth_freeAI(ai);
return fd;
}
+static int
+clear(int fd)
+{
+ return fd;
+}
+
+static char sslsecret[2][21];
+
+static int
+sslencrypt(int fd)
+{
+ return pushssl(fd, ealgs, sslsecret[0], sslsecret[1], nil);
+}
+
static void
mksecret(char *t, uchar *f)
{
f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
}
-/*
- * plan9 authentication followed by rc4 encryption
- */
static int
-p9auth(int fd)
+sslsetup(int fd, uchar *secret, int nsecret, int isclient)
{
- uchar key[16];
- uchar digest[SHA1dlen];
- char fromclientsecret[21];
- char fromserversecret[21];
+ uchar key[16], digest[SHA1dlen];
int i;
- AuthInfo *ai;
- procsetname("%s: auth_proxy proto=%q role=client %s",
- origargs, p9authproto, keyspec);
- ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", p9authproto, keyspec);
- if(ai == nil)
- return -1;
- memmove(key+4, ai->secret, ai->nsecret);
if(ealgs == nil)
return fd;
+ if(nsecret < 8){
+ werrstr("secret too small to ssl");
+ return -1;
+ }
+ memmove(key+4, secret, 8);
+
/* exchange random numbers */
srand(truerand());
- for(i = 0; i < 4; i++)
- key[i] = rand();
- procsetname("writing p9 key");
- if(write(fd, key, 4) != 4)
- return -1;
- procsetname("reading p9 key");
- if(readn(fd, key+12, 4) != 4)
- return -1;
+
+ if(isclient){
+ for(i = 0; i < 4; i++)
+ key[i] = rand();
+ if(write(fd, key, 4) != 4)
+ return -1;
+ if(readn(fd, key+12, 4) != 4)
+ return -1;
+ } else {
+ for(i = 0; i < 4; i++)
+ key[i+12] = rand();
+ if(readn(fd, key, 4) != 4)
+ return -1;
+ if(write(fd, key+12, 4) != 4)
+ return -1;
+ }
/* scramble into two secrets */
sha1(key, sizeof(key), digest, nil);
- mksecret(fromclientsecret, digest);
- mksecret(fromserversecret, digest+10);
-
- /* set up encryption */
- procsetname("pushssl");
- i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
- if(i < 0)
- werrstr("can't establish ssl connection: %r");
- return i;
+ mksecret(sslsecret[isclient == 0], digest);
+ mksecret(sslsecret[isclient != 0], digest+10);
+
+ encryption = sslencrypt;
+
+ return fd;
+}
+
+/*
+ * plan9 authentication followed by rc4 encryption
+ */
+static int
+p9auth(int fd)
+{
+ AuthInfo *ai;
+
+ ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
+ if(ai == nil)
+ return -1;
+ fd = sslsetup(fd, ai->secret, ai->nsecret, 1);
+ auth_freeAI(ai);
+ return fd;
}
static int
return fd;
}
-void
-loghex(uchar *p, int n)
-{
- char buf[100];
- int i;
-
- for(i = 0; i < n; i++)
- sprint(buf+2*i, "%2.2ux", p[i]);
- syslog(0, "cpu", buf);
-}
-
static int
srvp9auth(int fd, char *user)
{
- uchar key[16];
- uchar digest[SHA1dlen];
- char fromclientsecret[21];
- char fromserversecret[21];
- int i;
AuthInfo *ai;
- ai = auth_proxy(0, nil, "proto=%q role=server %s", p9authproto, keyspec);
+ ai = auth_proxy(fd, nil, "proto=p9any role=server %s", keyspec);
if(ai == nil)
return -1;
if(auth_chuid(ai, nil) < 0)
- return -1;
- strecpy(user, user+MaxStr, ai->cuid);
- memmove(key+4, ai->secret, ai->nsecret);
-
- if(ealgs == nil)
- return fd;
-
- /* exchange random numbers */
- srand(truerand());
- for(i = 0; i < 4; i++)
- key[i+12] = rand();
- if(readn(fd, key, 4) != 4)
- return -1;
- if(write(fd, key+12, 4) != 4)
- return -1;
-
- /* scramble into two secrets */
- sha1(key, sizeof(key), digest, nil);
- mksecret(fromclientsecret, digest);
- mksecret(fromserversecret, digest+10);
-
- /* set up encryption */
- i = pushssl(fd, ealgs, fromserversecret, fromclientsecret, nil);
- if(i < 0)
- werrstr("can't establish ssl connection: %r");
- return i;
+ fatal("newns: %r");
+ setnetuser(fd, ai->cuid);
+ snprint(user, MaxStr, "%s", ai->cuid);
+ fd = sslsetup(fd, ai->secret, ai->nsecret, 0);
+ auth_freeAI(ai);
+ return fd;
}
/*
return setam(s);
}
+int
+filter(int fd, char *host)
+{
+ char addr[128], buf[256], *s, *file, *argv[16];
+ int p[2], lfd, flags, len, argc;
+
+ if(filterp == nil)
+ return fd;
+ procsetname("filter %s", filterp);
+ flags = RFNOWAIT|RFPROC|RFMEM|RFFDG|RFREND;
+ if(host == nil){
+ /* remote side */
+ if(announce(anstring, addr) < 0)
+ fatal("filter: Cannot announce %s: %r", anstring);
+ snprint(buf, sizeof(buf), "%s/local", addr);
+ if((lfd = open(buf, OREAD)) < 0)
+ fatal("filter: Cannot open %s: %r", buf);
+ if((len = read(lfd, buf, sizeof buf - 1)) < 0)
+ fatal("filter: Cannot read %s: %r", buf);
+ close(lfd);
+ buf[len] = 0;
+ if(s = strchr(buf, '\n'))
+ len = s - buf;
+ if(write(fd, buf, len) != len)
+ fatal("filter: cannot write port; %r");
+ } else {
+ /* client side */
+ flags |= RFNOTEG;
+ if((len = read(fd, buf, sizeof buf - 1)) < 0)
+ fatal("filter: cannot read port; %r");
+ buf[len] = '\0';
+ if((s = strrchr(buf, '!')) == nil)
+ fatal("filter: malformed remote port: %s", buf);
+ strecpy(addr, addr+sizeof(addr), netmkaddr(host, "tcp", s+1));
+ strecpy(strrchr(addr, '!'), addr+sizeof(addr), s);
+ }
+
+ snprint(buf, sizeof(buf), "%s", filterp);
+ if((argc = tokenize(buf, argv, nelem(argv)-3)) <= 0)
+ fatal("filter: empty command");
+ if(host)
+ argv[argc++] = "-c";
+ argv[argc++] = addr;
+ argv[argc] = nil;
+ file = argv[0];
+ if(s = strrchr(argv[0], '/'))
+ argv[0] = s+1;
+
+ if(pipe(p) < 0)
+ fatal("filter: pipe; %r");
+
+ switch(rfork(flags)) {
+ case -1:
+ fatal("filter: rfork; %r\n");
+ case 0:
+ if (dup(p[0], 1) < 0)
+ fatal("filter: Cannot dup to 1; %r");
+ if (dup(p[0], 0) < 0)
+ fatal("filter: Cannot dup to 0; %r");
+ close(p[0]);
+ close(p[1]);
+ exec(file, argv);
+ fatal("filter: exec; %r");
+ default:
+ close(fd);
+ close(p[0]);
+ }
+ return p[1];
+}
+
char *rmtnotefile = "/mnt/term/dev/cpunote";
/*
_exits(0);
case 0:
fd = open(rmtnotefile, OREAD);
- if(fd < 0){
- syslog(0, "cpu", "cpu -R: can't open %s", rmtnotefile);
+ if(fd < 0)
_exits(0);
- }
for(;;){
n = read(fd, buf, sizeof(buf)-1);
ncpunote = 0;
for(;;){
n = read9pmsg(fd, buf, sizeof(buf));
- if(n <= 0){
- if(dbg)
- fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n);
- break;
- }
- if(convM2S(buf, n, &f) <= BIT16SZ)
+ if(n <= 0 || convM2S(buf, n, &f) != n)
break;
if(dbg)
fprint(2, "notefs: ->%F\n", &f);