163afb9a5SDavid du Colombier /*
263afb9a5SDavid du Colombier * ssh server - serve SSH protocol v2
363afb9a5SDavid du Colombier * /net/ssh does most of the work; we copy bytes back and forth
463afb9a5SDavid du Colombier */
563afb9a5SDavid du Colombier #include <u.h>
663afb9a5SDavid du Colombier #include <libc.h>
763afb9a5SDavid du Colombier #include <ip.h>
863afb9a5SDavid du Colombier #include <auth.h>
963afb9a5SDavid du Colombier #include "ssh2.h"
1063afb9a5SDavid du Colombier
1163afb9a5SDavid du Colombier char *confine(char *, char *);
1263afb9a5SDavid du Colombier char *get_string(char *, char *);
1363afb9a5SDavid du Colombier void newchannel(int, char *, int);
1463afb9a5SDavid du Colombier void runcmd(int, int, char *, char *, char *, char *);
1563afb9a5SDavid du Colombier
1663afb9a5SDavid du Colombier int errfd, toppid, sflag, tflag, prevent;
1763afb9a5SDavid du Colombier int debug;
1863afb9a5SDavid du Colombier char *idstring;
19*24d7e15eSDavid du Colombier char *netdir; /* /net/ssh/<conn> */
2063afb9a5SDavid du Colombier char *nsfile = nil;
2163afb9a5SDavid du Colombier char *restdir;
2263afb9a5SDavid du Colombier char *shell;
2363afb9a5SDavid du Colombier char *srvpt;
2463afb9a5SDavid du Colombier char *uname;
2563afb9a5SDavid du Colombier
2663afb9a5SDavid du Colombier void
usage(void)2763afb9a5SDavid du Colombier usage(void)
2863afb9a5SDavid du Colombier {
2963afb9a5SDavid du Colombier fprint(2, "usage: %s [-i id] [-s shell] [-r dir] [-R dir] [-S srvpt] "
3063afb9a5SDavid du Colombier "[-n ns] [-t] [netdir]\n", argv0);
3163afb9a5SDavid du Colombier exits("usage");
3263afb9a5SDavid du Colombier }
3363afb9a5SDavid du Colombier
3463afb9a5SDavid du Colombier static int
getctlfd(void)3563afb9a5SDavid du Colombier getctlfd(void)
3663afb9a5SDavid du Colombier {
3763afb9a5SDavid du Colombier int ctlfd;
3863afb9a5SDavid du Colombier char *name;
3963afb9a5SDavid du Colombier
4063afb9a5SDavid du Colombier name = smprint("%s/clone", netdir);
4163afb9a5SDavid du Colombier ctlfd = -1;
4263afb9a5SDavid du Colombier if (name)
4363afb9a5SDavid du Colombier ctlfd = open(name, ORDWR);
4463afb9a5SDavid du Colombier if (ctlfd < 0) {
4563afb9a5SDavid du Colombier syslog(0, "ssh", "server can't clone: %s: %r", name);
4663afb9a5SDavid du Colombier exits("open clone");
4763afb9a5SDavid du Colombier }
4863afb9a5SDavid du Colombier free(name);
4963afb9a5SDavid du Colombier return ctlfd;
5063afb9a5SDavid du Colombier }
5163afb9a5SDavid du Colombier
5263afb9a5SDavid du Colombier static int
getdatafd(int ctlfd)5363afb9a5SDavid du Colombier getdatafd(int ctlfd)
5463afb9a5SDavid du Colombier {
5563afb9a5SDavid du Colombier int fd;
5663afb9a5SDavid du Colombier char *name;
5763afb9a5SDavid du Colombier
5863afb9a5SDavid du Colombier name = smprint("%s/data", netdir);
5963afb9a5SDavid du Colombier fd = -1;
6063afb9a5SDavid du Colombier if (name)
6163afb9a5SDavid du Colombier fd = open(name, OREAD);
6263afb9a5SDavid du Colombier if (fd < 0) {
6363afb9a5SDavid du Colombier syslog(0, "ssh", "can't open %s: %r", name);
6463afb9a5SDavid du Colombier hangup(ctlfd);
6563afb9a5SDavid du Colombier exits("open data");
6663afb9a5SDavid du Colombier }
6763afb9a5SDavid du Colombier free(name);
6863afb9a5SDavid du Colombier return fd;
6963afb9a5SDavid du Colombier }
7063afb9a5SDavid du Colombier
7163afb9a5SDavid du Colombier static void
auth(char * buf,int n,int ctlfd)7263afb9a5SDavid du Colombier auth(char *buf, int n, int ctlfd)
7363afb9a5SDavid du Colombier {
7463afb9a5SDavid du Colombier int fd;
7563afb9a5SDavid du Colombier
7663afb9a5SDavid du Colombier fd = open("#¤/capuse", OWRITE);
7763afb9a5SDavid du Colombier if (fd < 0) {
7863afb9a5SDavid du Colombier syslog(0, "ssh", "server can't open capuse: %r");
7963afb9a5SDavid du Colombier hangup(ctlfd);
8063afb9a5SDavid du Colombier exits("capuse");
8163afb9a5SDavid du Colombier }
8263afb9a5SDavid du Colombier if (write(fd, buf, n) != n) {
8363afb9a5SDavid du Colombier syslog(0, "ssh", "server write `%.*s' to capuse failed: %r",
8463afb9a5SDavid du Colombier n, buf);
8563afb9a5SDavid du Colombier hangup(ctlfd);
8663afb9a5SDavid du Colombier exits("capuse");
8763afb9a5SDavid du Colombier }
8863afb9a5SDavid du Colombier close(fd);
8963afb9a5SDavid du Colombier }
9063afb9a5SDavid du Colombier
9163afb9a5SDavid du Colombier /*
92*24d7e15eSDavid du Colombier * mount tunnel if there isn't one visible.
9363afb9a5SDavid du Colombier */
9463afb9a5SDavid du Colombier static void
mounttunnel(int ctlfd)9563afb9a5SDavid du Colombier mounttunnel(int ctlfd)
9663afb9a5SDavid du Colombier {
9763afb9a5SDavid du Colombier int fd;
98*24d7e15eSDavid du Colombier char *p, *np, *q;
9963afb9a5SDavid du Colombier
10063afb9a5SDavid du Colombier if (access(netdir, AEXIST) >= 0)
10163afb9a5SDavid du Colombier return;
10263afb9a5SDavid du Colombier
10363afb9a5SDavid du Colombier p = smprint("/srv/%s", srvpt? srvpt: "ssh");
104*24d7e15eSDavid du Colombier np = strdup(netdir);
105*24d7e15eSDavid du Colombier if (p == nil || np == nil)
106*24d7e15eSDavid du Colombier sysfatal("out of memory");
107*24d7e15eSDavid du Colombier q = strstr(np, "/ssh");
108*24d7e15eSDavid du Colombier if (q != nil)
109*24d7e15eSDavid du Colombier *q = '\0';
11063afb9a5SDavid du Colombier fd = open(p, ORDWR);
11163afb9a5SDavid du Colombier if (fd < 0) {
11263afb9a5SDavid du Colombier syslog(0, "ssh", "can't open %s: %r", p);
11363afb9a5SDavid du Colombier hangup(ctlfd);
11463afb9a5SDavid du Colombier exits("open");
11563afb9a5SDavid du Colombier }
116*24d7e15eSDavid du Colombier if (mount(fd, -1, np, MBEFORE, "") < 0) {
117*24d7e15eSDavid du Colombier syslog(0, "ssh", "can't mount %s in %s: %r", p, np);
11863afb9a5SDavid du Colombier hangup(ctlfd);
11963afb9a5SDavid du Colombier exits("can't mount");
12063afb9a5SDavid du Colombier }
121*24d7e15eSDavid du Colombier free(p);
122*24d7e15eSDavid du Colombier free(np);
12363afb9a5SDavid du Colombier }
12463afb9a5SDavid du Colombier
12563afb9a5SDavid du Colombier static int
authnewns(int ctlfd,char * buf,int size,int n)12663afb9a5SDavid du Colombier authnewns(int ctlfd, char *buf, int size, int n)
12763afb9a5SDavid du Colombier {
12863afb9a5SDavid du Colombier char *p, *q;
12963afb9a5SDavid du Colombier
13063afb9a5SDavid du Colombier USED(size);
13163afb9a5SDavid du Colombier if (n <= 0)
13263afb9a5SDavid du Colombier return 0;
13363afb9a5SDavid du Colombier buf[n] = '\0';
13463afb9a5SDavid du Colombier if (strcmp(buf, "n/a") == 0)
13563afb9a5SDavid du Colombier return 0;
13663afb9a5SDavid du Colombier
13763afb9a5SDavid du Colombier auth(buf, n, ctlfd);
13863afb9a5SDavid du Colombier
13963afb9a5SDavid du Colombier p = strchr(buf, '@');
14063afb9a5SDavid du Colombier if (p == nil)
14163afb9a5SDavid du Colombier return 0;
14263afb9a5SDavid du Colombier ++p;
14363afb9a5SDavid du Colombier q = strchr(p, '@');
14463afb9a5SDavid du Colombier if (q) {
14563afb9a5SDavid du Colombier *q = '\0';
14663afb9a5SDavid du Colombier uname = strdup(p);
14763afb9a5SDavid du Colombier }
14863afb9a5SDavid du Colombier if (!tflag && newns(p, nsfile) < 0) {
14963afb9a5SDavid du Colombier syslog(0, "ssh", "server: newns(%s,%s) failed: %r", p, nsfile);
15063afb9a5SDavid du Colombier return -1;
15163afb9a5SDavid du Colombier }
15263afb9a5SDavid du Colombier return 0;
15363afb9a5SDavid du Colombier }
15463afb9a5SDavid du Colombier
15563afb9a5SDavid du Colombier static void
listenloop(char * listfile,int ctlfd,char * buf,int size)15663afb9a5SDavid du Colombier listenloop(char *listfile, int ctlfd, char *buf, int size)
15763afb9a5SDavid du Colombier {
15863afb9a5SDavid du Colombier int fd, n;
15963afb9a5SDavid du Colombier
16063afb9a5SDavid du Colombier while ((fd = open(listfile, ORDWR)) >= 0) {
16163afb9a5SDavid du Colombier n = read(fd, buf, size - 1);
16263afb9a5SDavid du Colombier fprint(errfd, "read from listen file returned %d\n", n);
16363afb9a5SDavid du Colombier if (n <= 0) {
16463afb9a5SDavid du Colombier syslog(0, "ssh", "read on listen failed: %r");
16563afb9a5SDavid du Colombier break;
16663afb9a5SDavid du Colombier }
16763afb9a5SDavid du Colombier buf[n >= 0? n: 0] = '\0';
16863afb9a5SDavid du Colombier fprint(errfd, "read %s\n", buf);
16963afb9a5SDavid du Colombier
17063afb9a5SDavid du Colombier switch (fork()) {
17163afb9a5SDavid du Colombier case 0: /* child */
17263afb9a5SDavid du Colombier close(ctlfd);
17363afb9a5SDavid du Colombier newchannel(fd, netdir, atoi(buf)); /* never returns */
17463afb9a5SDavid du Colombier case -1:
17563afb9a5SDavid du Colombier syslog(0, "ssh", "fork failed: %r");
17663afb9a5SDavid du Colombier hangup(ctlfd);
17763afb9a5SDavid du Colombier exits("fork");
17863afb9a5SDavid du Colombier }
17963afb9a5SDavid du Colombier close(fd);
18063afb9a5SDavid du Colombier }
18163afb9a5SDavid du Colombier if (fd < 0)
18263afb9a5SDavid du Colombier syslog(0, "ssh", "listen failed: %r");
18363afb9a5SDavid du Colombier }
18463afb9a5SDavid du Colombier
18563afb9a5SDavid du Colombier void
main(int argc,char * argv[])18663afb9a5SDavid du Colombier main(int argc, char *argv[])
18763afb9a5SDavid du Colombier {
18863afb9a5SDavid du Colombier char *listfile;
18963afb9a5SDavid du Colombier int ctlfd, fd, n;
19063afb9a5SDavid du Colombier char buf[Arbpathlen], path[Arbpathlen];
19163afb9a5SDavid du Colombier
19263afb9a5SDavid du Colombier rfork(RFNOTEG);
19363afb9a5SDavid du Colombier toppid = getpid();
19463afb9a5SDavid du Colombier shell = "/bin/rc -il";
19563afb9a5SDavid du Colombier ARGBEGIN {
19663afb9a5SDavid du Colombier case 'd':
19763afb9a5SDavid du Colombier debug++;
19863afb9a5SDavid du Colombier break;
19963afb9a5SDavid du Colombier case 'i':
20063afb9a5SDavid du Colombier idstring = EARGF(usage());
20163afb9a5SDavid du Colombier break;
20263afb9a5SDavid du Colombier case 'n':
20363afb9a5SDavid du Colombier nsfile = EARGF(usage());
20463afb9a5SDavid du Colombier break;
20563afb9a5SDavid du Colombier case 'R':
20663afb9a5SDavid du Colombier prevent = 1;
20763afb9a5SDavid du Colombier /* fall through */
20863afb9a5SDavid du Colombier case 'r':
20963afb9a5SDavid du Colombier restdir = EARGF(usage());
21063afb9a5SDavid du Colombier break;
21163afb9a5SDavid du Colombier case 's':
21263afb9a5SDavid du Colombier sflag = 1;
21363afb9a5SDavid du Colombier shell = EARGF(usage());
21463afb9a5SDavid du Colombier break;
21563afb9a5SDavid du Colombier case 'S':
21663afb9a5SDavid du Colombier srvpt = EARGF(usage());
21763afb9a5SDavid du Colombier break;
21863afb9a5SDavid du Colombier case 't':
21963afb9a5SDavid du Colombier tflag = 1;
22063afb9a5SDavid du Colombier break;
22163afb9a5SDavid du Colombier default:
22263afb9a5SDavid du Colombier usage();
22363afb9a5SDavid du Colombier break;
22463afb9a5SDavid du Colombier } ARGEND;
22563afb9a5SDavid du Colombier
22663afb9a5SDavid du Colombier errfd = -1;
22763afb9a5SDavid du Colombier if (debug)
22863afb9a5SDavid du Colombier errfd = 2;
22963afb9a5SDavid du Colombier
23063afb9a5SDavid du Colombier /* work out network connection's directory */
23163afb9a5SDavid du Colombier if (argc >= 1)
23263afb9a5SDavid du Colombier netdir = argv[0];
23363afb9a5SDavid du Colombier else /* invoked by listen1 */
23463afb9a5SDavid du Colombier netdir = getenv("net");
23563afb9a5SDavid du Colombier if (netdir == nil) {
23663afb9a5SDavid du Colombier syslog(0, "ssh", "server netdir is nil");
23763afb9a5SDavid du Colombier exits("nil netdir");
23863afb9a5SDavid du Colombier }
23963afb9a5SDavid du Colombier syslog(0, "ssh", "server netdir is %s", netdir);
24063afb9a5SDavid du Colombier
24163afb9a5SDavid du Colombier uname = getenv("user");
24263afb9a5SDavid du Colombier if (uname == nil)
24363afb9a5SDavid du Colombier uname = "none";
24463afb9a5SDavid du Colombier
24563afb9a5SDavid du Colombier /* extract dfd and cfd from netdir */
24663afb9a5SDavid du Colombier ctlfd = getctlfd();
24763afb9a5SDavid du Colombier fd = getdatafd(ctlfd);
24863afb9a5SDavid du Colombier
24963afb9a5SDavid du Colombier n = read(fd, buf, sizeof buf - 1);
25063afb9a5SDavid du Colombier if (n < 0) {
25163afb9a5SDavid du Colombier syslog(0, "ssh", "server read error for data file: %r");
25263afb9a5SDavid du Colombier hangup(ctlfd);
25363afb9a5SDavid du Colombier exits("read cap");
25463afb9a5SDavid du Colombier }
25563afb9a5SDavid du Colombier close(fd);
25663afb9a5SDavid du Colombier authnewns(ctlfd, buf, sizeof buf, n);
25763afb9a5SDavid du Colombier
25863afb9a5SDavid du Colombier /* get connection number in buf */
25963afb9a5SDavid du Colombier n = read(ctlfd, buf, sizeof buf - 1);
26063afb9a5SDavid du Colombier buf[n >= 0? n: 0] = '\0';
26163afb9a5SDavid du Colombier
26263afb9a5SDavid du Colombier /* tell netssh our id string */
26363afb9a5SDavid du Colombier fd2path(ctlfd, path, sizeof path);
26463afb9a5SDavid du Colombier if (0 && idstring) { /* was for coexistence */
26563afb9a5SDavid du Colombier syslog(0, "ssh", "server conn %s, writing \"id %s\" to %s",
26663afb9a5SDavid du Colombier buf, idstring, path);
26763afb9a5SDavid du Colombier fprint(ctlfd, "id %s", idstring);
26863afb9a5SDavid du Colombier }
26963afb9a5SDavid du Colombier
27063afb9a5SDavid du Colombier /* announce */
27163afb9a5SDavid du Colombier fprint(ctlfd, "announce session");
27263afb9a5SDavid du Colombier
27363afb9a5SDavid du Colombier /* construct listen file name */
27463afb9a5SDavid du Colombier listfile = smprint("%s/%s/listen", netdir, buf);
27563afb9a5SDavid du Colombier if (listfile == nil) {
27663afb9a5SDavid du Colombier syslog(0, "ssh", "out of memory");
27763afb9a5SDavid du Colombier exits("out of memory");
27863afb9a5SDavid du Colombier }
27963afb9a5SDavid du Colombier syslog(0, "ssh", "server listen is %s", listfile);
28063afb9a5SDavid du Colombier
28163afb9a5SDavid du Colombier mounttunnel(ctlfd);
28263afb9a5SDavid du Colombier listenloop(listfile, ctlfd, buf, sizeof buf);
28363afb9a5SDavid du Colombier hangup(ctlfd);
28463afb9a5SDavid du Colombier exits(nil);
28563afb9a5SDavid du Colombier }
28663afb9a5SDavid du Colombier
28763afb9a5SDavid du Colombier /* an abbreviation. note the assumed variables. */
28863afb9a5SDavid du Colombier #define REPLY(s) if (want_reply) fprint(reqfd, s);
28963afb9a5SDavid du Colombier
29063afb9a5SDavid du Colombier static void
forkshell(char * cmd,int reqfd,int datafd,int want_reply)29163afb9a5SDavid du Colombier forkshell(char *cmd, int reqfd, int datafd, int want_reply)
29263afb9a5SDavid du Colombier {
29363afb9a5SDavid du Colombier switch (fork()) {
29463afb9a5SDavid du Colombier case 0:
29563afb9a5SDavid du Colombier if (sflag)
29663afb9a5SDavid du Colombier snprint(cmd, sizeof cmd, "-s%s", shell);
29763afb9a5SDavid du Colombier else
29863afb9a5SDavid du Colombier cmd[0] = '\0';
29963afb9a5SDavid du Colombier USED(cmd);
30063afb9a5SDavid du Colombier syslog(0, "ssh", "server starting ssh shell for %s", uname);
30163afb9a5SDavid du Colombier /* runcmd doesn't return */
30263afb9a5SDavid du Colombier runcmd(reqfd, datafd, "con", "/bin/ip/telnetd", "-nt", nil);
30363afb9a5SDavid du Colombier case -1:
30463afb9a5SDavid du Colombier REPLY("failure");
30563afb9a5SDavid du Colombier syslog(0, "ssh", "server can't fork: %r");
30663afb9a5SDavid du Colombier exits("fork");
30763afb9a5SDavid du Colombier }
30863afb9a5SDavid du Colombier }
30963afb9a5SDavid du Colombier
31063afb9a5SDavid du Colombier static void
forkcmd(char * cmd,char * p,int reqfd,int datafd,int want_reply)31163afb9a5SDavid du Colombier forkcmd(char *cmd, char *p, int reqfd, int datafd, int want_reply)
31263afb9a5SDavid du Colombier {
31363afb9a5SDavid du Colombier char *q;
31463afb9a5SDavid du Colombier
31563afb9a5SDavid du Colombier switch (fork()) {
31663afb9a5SDavid du Colombier case 0:
31763afb9a5SDavid du Colombier if (restdir && chdir(restdir) < 0) {
31863afb9a5SDavid du Colombier syslog(0, "ssh", "can't chdir(%s): %r", restdir);
31963afb9a5SDavid du Colombier exits("can't chdir");
32063afb9a5SDavid du Colombier }
32163afb9a5SDavid du Colombier if (!prevent || (q = getenv("sshsession")) &&
32263afb9a5SDavid du Colombier strcmp(q, "allow") == 0)
32363afb9a5SDavid du Colombier get_string(p+1, cmd);
32463afb9a5SDavid du Colombier else
32563afb9a5SDavid du Colombier confine(p+1, cmd);
32663afb9a5SDavid du Colombier syslog(0, "ssh", "server running `%s' for %s", cmd, uname);
32763afb9a5SDavid du Colombier /* runcmd doesn't return */
32863afb9a5SDavid du Colombier runcmd(reqfd, datafd, "rx", "/bin/rc", "-lc", cmd);
32963afb9a5SDavid du Colombier case -1:
33063afb9a5SDavid du Colombier REPLY("failure");
33163afb9a5SDavid du Colombier syslog(0, "ssh", "server can't fork: %r");
33263afb9a5SDavid du Colombier exits("fork");
33363afb9a5SDavid du Colombier }
33463afb9a5SDavid du Colombier }
33563afb9a5SDavid du Colombier
33663afb9a5SDavid du Colombier void
newchannel(int fd,char * conndir,int channum)33763afb9a5SDavid du Colombier newchannel(int fd, char *conndir, int channum)
33863afb9a5SDavid du Colombier {
33963afb9a5SDavid du Colombier char *p, *reqfile, *datafile;
34063afb9a5SDavid du Colombier int n, reqfd, datafd, want_reply, already_done;
34163afb9a5SDavid du Colombier char buf[Maxpayload], cmd[Bigbufsz];
34263afb9a5SDavid du Colombier
34363afb9a5SDavid du Colombier close(fd);
34463afb9a5SDavid du Colombier
34563afb9a5SDavid du Colombier already_done = 0;
34663afb9a5SDavid du Colombier reqfile = smprint("%s/%d/request", conndir, channum);
34763afb9a5SDavid du Colombier if (reqfile == nil)
34863afb9a5SDavid du Colombier sysfatal("out of memory");
34963afb9a5SDavid du Colombier reqfd = open(reqfile, ORDWR);
35063afb9a5SDavid du Colombier if (reqfd < 0) {
35163afb9a5SDavid du Colombier syslog(0, "ssh", "can't open request file %s: %r", reqfile);
35263afb9a5SDavid du Colombier exits("net");
35363afb9a5SDavid du Colombier }
35463afb9a5SDavid du Colombier datafile = smprint("%s/%d/data", conndir, channum);
35563afb9a5SDavid du Colombier if (datafile == nil)
35663afb9a5SDavid du Colombier sysfatal("out of memory");
35763afb9a5SDavid du Colombier datafd = open(datafile, ORDWR);
35863afb9a5SDavid du Colombier if (datafd < 0) {
35963afb9a5SDavid du Colombier syslog(0, "ssh", "can't open data file %s: %r", datafile);
36063afb9a5SDavid du Colombier exits("net");
36163afb9a5SDavid du Colombier }
36263afb9a5SDavid du Colombier while ((n = read(reqfd, buf, sizeof buf - 1)) > 0) {
36363afb9a5SDavid du Colombier fprint(errfd, "read from request file returned %d\n", n);
36463afb9a5SDavid du Colombier for (p = buf; p < buf + n && *p != ' '; ++p)
36563afb9a5SDavid du Colombier ;
36663afb9a5SDavid du Colombier *p++ = '\0';
36763afb9a5SDavid du Colombier want_reply = (*p == 't');
36863afb9a5SDavid du Colombier /* shell, exec, and various flavours of failure */
36963afb9a5SDavid du Colombier if (strcmp(buf, "shell") == 0) {
37063afb9a5SDavid du Colombier if (already_done) {
37163afb9a5SDavid du Colombier REPLY("failure");
37263afb9a5SDavid du Colombier continue;
37363afb9a5SDavid du Colombier }
37463afb9a5SDavid du Colombier forkshell(cmd, reqfd, datafd, want_reply);
37563afb9a5SDavid du Colombier already_done = 1;
37663afb9a5SDavid du Colombier REPLY("success");
37763afb9a5SDavid du Colombier } else if (strcmp(buf, "exec") == 0) {
37863afb9a5SDavid du Colombier if (already_done) {
37963afb9a5SDavid du Colombier REPLY("failure");
38063afb9a5SDavid du Colombier continue;
38163afb9a5SDavid du Colombier }
38263afb9a5SDavid du Colombier forkcmd(cmd, p, reqfd, datafd, want_reply);
38363afb9a5SDavid du Colombier already_done = 1;
38463afb9a5SDavid du Colombier REPLY("success");
38563afb9a5SDavid du Colombier } else if (strcmp(buf, "pty-req") == 0 ||
38663afb9a5SDavid du Colombier strcmp(buf, "window-change") == 0) {
38763afb9a5SDavid du Colombier REPLY("success");
38863afb9a5SDavid du Colombier } else if (strcmp(buf, "x11-req") == 0 ||
38963afb9a5SDavid du Colombier strcmp(buf, "env") == 0 || strcmp(buf, "subsystem") == 0) {
39063afb9a5SDavid du Colombier REPLY("failure");
39163afb9a5SDavid du Colombier } else if (strcmp(buf, "xon-xoff") == 0 ||
39263afb9a5SDavid du Colombier strcmp(buf, "signal") == 0 ||
39363afb9a5SDavid du Colombier strcmp(buf, "exit-status") == 0 ||
39463afb9a5SDavid du Colombier strcmp(buf, "exit-signal") == 0) {
39563afb9a5SDavid du Colombier ;
39663afb9a5SDavid du Colombier } else
39763afb9a5SDavid du Colombier syslog(0, "ssh", "server unknown channel request: %s",
39863afb9a5SDavid du Colombier buf);
39963afb9a5SDavid du Colombier }
40063afb9a5SDavid du Colombier if (n < 0)
40163afb9a5SDavid du Colombier syslog(0, "ssh", "server read failed: %r");
40263afb9a5SDavid du Colombier exits(nil);
40363afb9a5SDavid du Colombier }
40463afb9a5SDavid du Colombier
40563afb9a5SDavid du Colombier char *
get_string(char * q,char * s)40663afb9a5SDavid du Colombier get_string(char *q, char *s)
40763afb9a5SDavid du Colombier {
40863afb9a5SDavid du Colombier int n;
40963afb9a5SDavid du Colombier
41063afb9a5SDavid du Colombier n = nhgetl(q);
41163afb9a5SDavid du Colombier q += 4;
41263afb9a5SDavid du Colombier memmove(s, q, n);
41363afb9a5SDavid du Colombier s[n] = '\0';
41463afb9a5SDavid du Colombier q += n;
41563afb9a5SDavid du Colombier return q;
41663afb9a5SDavid du Colombier }
41763afb9a5SDavid du Colombier
41863afb9a5SDavid du Colombier char *
confine(char * q,char * s)41963afb9a5SDavid du Colombier confine(char *q, char *s)
42063afb9a5SDavid du Colombier {
42163afb9a5SDavid du Colombier int i, n, m;
42263afb9a5SDavid du Colombier char *p, *e, *r, *buf, *toks[Maxtoks];
42363afb9a5SDavid du Colombier
42463afb9a5SDavid du Colombier n = nhgetl(q);
42563afb9a5SDavid du Colombier q += 4;
42663afb9a5SDavid du Colombier buf = malloc(n+1);
42763afb9a5SDavid du Colombier if (buf == nil)
42863afb9a5SDavid du Colombier return nil;
42963afb9a5SDavid du Colombier memmove(buf, q, n);
43063afb9a5SDavid du Colombier buf[n] = 0;
43163afb9a5SDavid du Colombier m = tokenize(buf, toks, nelem(toks));
43263afb9a5SDavid du Colombier e = s + n + 1;
43363afb9a5SDavid du Colombier for (i = 0, r = s; i < m; ++i) {
43463afb9a5SDavid du Colombier p = strrchr(toks[i], '/');
43563afb9a5SDavid du Colombier if (p == nil)
43663afb9a5SDavid du Colombier r = seprint(r, e, "%s ", toks[i]);
43763afb9a5SDavid du Colombier else if (p[0] != '\0' && p[1] != '\0')
43863afb9a5SDavid du Colombier r = seprint(r, e, "%s ", p+1);
43963afb9a5SDavid du Colombier else
44063afb9a5SDavid du Colombier r = seprint(r, e, ". ");
44163afb9a5SDavid du Colombier }
44263afb9a5SDavid du Colombier free(buf);
44363afb9a5SDavid du Colombier q += n;
44463afb9a5SDavid du Colombier return q;
44563afb9a5SDavid du Colombier }
44663afb9a5SDavid du Colombier
44763afb9a5SDavid du Colombier void
runcmd(int reqfd,int datafd,char * svc,char * cmd,char * arg1,char * arg2)44863afb9a5SDavid du Colombier runcmd(int reqfd, int datafd, char *svc, char *cmd, char *arg1, char *arg2)
44963afb9a5SDavid du Colombier {
45063afb9a5SDavid du Colombier char *p;
45163afb9a5SDavid du Colombier int fd, cmdpid, child;
45263afb9a5SDavid du Colombier
45363afb9a5SDavid du Colombier cmdpid = rfork(RFPROC|RFMEM|RFNOTEG|RFFDG|RFENVG);
45463afb9a5SDavid du Colombier switch (cmdpid) {
45563afb9a5SDavid du Colombier case -1:
45663afb9a5SDavid du Colombier syslog(0, "ssh", "fork failed: %r");
45763afb9a5SDavid du Colombier exits("fork");
45863afb9a5SDavid du Colombier case 0:
45963afb9a5SDavid du Colombier if (restdir == nil) {
46063afb9a5SDavid du Colombier p = smprint("/usr/%s", uname);
46163afb9a5SDavid du Colombier if (p && access(p, AREAD) == 0 && chdir(p) < 0) {
46263afb9a5SDavid du Colombier syslog(0, "ssh", "can't chdir(%s): %r", p);
46363afb9a5SDavid du Colombier exits("can't chdir");
46463afb9a5SDavid du Colombier }
46563afb9a5SDavid du Colombier free(p);
46663afb9a5SDavid du Colombier }
46763afb9a5SDavid du Colombier p = strrchr(cmd, '/');
46863afb9a5SDavid du Colombier if (p)
46963afb9a5SDavid du Colombier ++p;
47063afb9a5SDavid du Colombier else
47163afb9a5SDavid du Colombier p = cmd;
47263afb9a5SDavid du Colombier
47363afb9a5SDavid du Colombier dup(datafd, 0);
47463afb9a5SDavid du Colombier dup(datafd, 1);
47563afb9a5SDavid du Colombier dup(datafd, 2);
47663afb9a5SDavid du Colombier close(datafd);
47763afb9a5SDavid du Colombier putenv("service", svc);
47863afb9a5SDavid du Colombier fprint(errfd, "starting %s\n", cmd);
47963afb9a5SDavid du Colombier execl(cmd, p, arg1, arg2, nil);
48063afb9a5SDavid du Colombier
48163afb9a5SDavid du Colombier syslog(0, "ssh", "cannot exec %s: %r", cmd);
48263afb9a5SDavid du Colombier exits("exec");
48363afb9a5SDavid du Colombier default:
48463afb9a5SDavid du Colombier close(datafd);
48563afb9a5SDavid du Colombier fprint(errfd, "waiting for child %d\n", cmdpid);
48663afb9a5SDavid du Colombier while ((child = waitpid()) != cmdpid && child != -1)
48763afb9a5SDavid du Colombier fprint(errfd, "child %d passed\n", child);
48863afb9a5SDavid du Colombier if (child == -1)
48963afb9a5SDavid du Colombier fprint(errfd, "wait failed: %r\n");
49063afb9a5SDavid du Colombier
49163afb9a5SDavid du Colombier syslog(0, "ssh", "server closing ssh session for %s", uname);
49263afb9a5SDavid du Colombier fprint(errfd, "closing connection\n");
49363afb9a5SDavid du Colombier fprint(reqfd, "close");
49463afb9a5SDavid du Colombier p = smprint("/proc/%d/notepg", toppid);
49563afb9a5SDavid du Colombier if (p) {
49663afb9a5SDavid du Colombier fd = open(p, OWRITE);
49763afb9a5SDavid du Colombier fprint(fd, "interrupt");
49863afb9a5SDavid du Colombier close(fd);
49963afb9a5SDavid du Colombier }
50063afb9a5SDavid du Colombier exits(nil);
50163afb9a5SDavid du Colombier }
50263afb9a5SDavid du Colombier }
503