summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ssh/sshserve.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ssh/sshserve.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ssh/sshserve.c')
-rwxr-xr-xsys/src/cmd/ssh/sshserve.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/sys/src/cmd/ssh/sshserve.c b/sys/src/cmd/ssh/sshserve.c
new file mode 100755
index 000000000..87b0536c5
--- /dev/null
+++ b/sys/src/cmd/ssh/sshserve.c
@@ -0,0 +1,315 @@
+#include "ssh.h"
+
+char *cipherlist = "blowfish rc4 3des";
+char *authlist = "tis";
+
+void fromnet(Conn*);
+void startcmd(Conn*, char*, int*, int*);
+int maxmsg = 256*1024;
+
+Cipher *allcipher[] = {
+ &cipherrc4,
+ &cipherblowfish,
+ &cipher3des,
+ &cipherdes,
+ &ciphernone,
+ &ciphertwiddle,
+};
+
+Authsrv *allauthsrv[] = {
+ &authsrvpassword,
+ &authsrvtis,
+};
+
+Cipher*
+findcipher(char *name, Cipher **list, int nlist)
+{
+ int i;
+
+ for(i=0; i<nlist; i++)
+ if(strcmp(name, list[i]->name) == 0)
+ return list[i];
+ error("unknown cipher %s", name);
+ return nil;
+}
+
+Authsrv*
+findauthsrv(char *name, Authsrv **list, int nlist)
+{
+ int i;
+
+ for(i=0; i<nlist; i++)
+ if(strcmp(name, list[i]->name) == 0)
+ return list[i];
+ error("unknown authsrv %s", name);
+ return nil;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: sshserve [-A authlist] [-c cipherlist] client-ip-address\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *f[16];
+ int i;
+ Conn c;
+
+ fmtinstall('B', mpfmt);
+ fmtinstall('H', encodefmt);
+ atexit(atexitkiller);
+ atexitkill(getpid());
+
+ memset(&c, 0, sizeof c);
+
+ ARGBEGIN{
+ case 'D':
+ debuglevel = atoi(EARGF(usage()));
+ break;
+ case 'A':
+ authlist = EARGF(usage());
+ break;
+ case 'c':
+ cipherlist = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+ c.host = argv[0];
+
+ sshlog("connect from %s", c.host);
+
+ /* limit of 768 bits in remote host key? */
+ c.serverpriv = rsagen(768, 6, 0);
+ if(c.serverpriv == nil)
+ sysfatal("rsagen failed: %r");
+ c.serverkey = &c.serverpriv->pub;
+
+ c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", ");
+ c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher);
+ for(i=0; i<c.nokcipher; i++)
+ c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher));
+
+ c.nokauthsrv = getfields(authlist, f, nelem(f), 1, ", ");
+ c.okauthsrv = emalloc(sizeof(Authsrv*)*c.nokauthsrv);
+ for(i=0; i<c.nokauthsrv; i++)
+ c.okauthsrv[i] = findauthsrv(f[i], allauthsrv, nelem(allauthsrv));
+
+ sshserverhandshake(&c);
+
+ fromnet(&c);
+}
+
+void
+fromnet(Conn *c)
+{
+ int infd, kidpid, n;
+ char *cmd;
+ Msg *m;
+
+ infd = kidpid = -1;
+ for(;;){
+ m = recvmsg(c, -1);
+ if(m == nil)
+ exits(nil);
+ switch(m->type){
+ default:
+ //badmsg(m, 0);
+ sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
+ break;
+
+ case SSH_MSG_DISCONNECT:
+ sysfatal("client disconnected");
+
+ case SSH_CMSG_REQUEST_PTY:
+ sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
+ break;
+
+ case SSH_CMSG_X11_REQUEST_FORWARDING:
+ sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
+ break;
+
+ case SSH_CMSG_MAX_PACKET_SIZE:
+ maxmsg = getlong(m);
+ sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
+ break;
+
+ case SSH_CMSG_REQUEST_COMPRESSION:
+ sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
+ break;
+
+ case SSH_CMSG_EXEC_SHELL:
+ startcmd(c, nil, &kidpid, &infd);
+ goto InteractiveMode;
+
+ case SSH_CMSG_EXEC_CMD:
+ cmd = getstring(m);
+ startcmd(c, cmd, &kidpid, &infd);
+ goto InteractiveMode;
+ }
+ free(m);
+ }
+
+InteractiveMode:
+ for(;;){
+ free(m);
+ m = recvmsg(c, -1);
+ if(m == nil)
+ exits(nil);
+ switch(m->type){
+ default:
+ badmsg(m, 0);
+
+ case SSH_MSG_DISCONNECT:
+ postnote(PNGROUP, kidpid, "hangup");
+ sysfatal("client disconnected");
+
+ case SSH_CMSG_STDIN_DATA:
+ if(infd != 0){
+ n = getlong(m);
+ write(infd, getbytes(m, n), n);
+ }
+ break;
+
+ case SSH_CMSG_EOF:
+ close(infd);
+ infd = -1;
+ break;
+
+ case SSH_CMSG_EXIT_CONFIRMATION:
+ /* sent by some clients as dying breath */
+ exits(nil);
+
+ case SSH_CMSG_WINDOW_SIZE:
+ /* we don't care */
+ break;
+ }
+ }
+}
+
+void
+copyout(Conn *c, int fd, int mtype)
+{
+ char buf[8192];
+ int n, max, pid;
+ Msg *m;
+
+ max = sizeof buf;
+ if(max > maxmsg - 32) /* 32 is an overestimate of packet overhead */
+ max = maxmsg - 32;
+ if(max <= 0)
+ sysfatal("maximum message size too small");
+
+ switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ break;
+ default:
+ atexitkill(pid);
+ return;
+ }
+
+ while((n = read(fd, buf, max)) > 0){
+ m = allocmsg(c, mtype, 4+n);
+ putlong(m, n);
+ putbytes(m, buf, n);
+ sendmsg(m);
+ }
+ exits(nil);
+}
+
+void
+startcmd(Conn *c, char *cmd, int *kidpid, int *kidin)
+{
+ int i, pid, kpid;
+ int pfd[3][2];
+ char *dir;
+ char *sysname, *tz;
+ Msg *m;
+ Waitmsg *w;
+
+ for(i=0; i<3; i++)
+ if(pipe(pfd[i]) < 0)
+ sysfatal("pipe: %r");
+
+ sysname = getenv("sysname");
+ tz = getenv("timezone");
+
+ switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ switch(kpid = rfork(RFPROC|RFNOTEG|RFENVG|RFFDG)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ for(i=0; i<3; i++){
+ if(dup(pfd[i][1], i) < 0)
+ sysfatal("dup: %r");
+ close(pfd[i][0]);
+ close(pfd[i][1]);
+ }
+ putenv("user", c->user);
+ if(sysname)
+ putenv("sysname", sysname);
+ if(tz)
+ putenv("tz", tz);
+
+ dir = smprint("/usr/%s", c->user);
+ if(dir == nil || chdir(dir) < 0)
+ chdir("/");
+ if(cmd){
+ putenv("service", "rx");
+ execl("/bin/rc", "rc", "-lc", cmd, nil);
+ sysfatal("cannot exec /bin/rc: %r");
+ }else{
+ putenv("service", "con");
+ execl("/bin/ip/telnetd", "telnetd", "-tn", nil);
+ sysfatal("cannot exec /bin/ip/telnetd: %r");
+ }
+ default:
+ *kidpid = kpid;
+ rendezvous(kidpid, 0);
+ for(;;){
+ if((w = wait()) == nil)
+ sysfatal("wait: %r");
+ if(w->pid == kpid)
+ break;
+ free(w);
+ }
+ if(w->msg[0]){
+ m = allocmsg(c, SSH_MSG_DISCONNECT, 4+strlen(w->msg));
+ putstring(m, w->msg);
+ sendmsg(m);
+ }else{
+ m = allocmsg(c, SSH_SMSG_EXITSTATUS, 4);
+ putlong(m, 0);
+ sendmsg(m);
+ }
+ for(i=0; i<3; i++)
+ close(pfd[i][0]);
+ free(w);
+ exits(nil);
+ break;
+ }
+ default:
+ atexitkill(pid);
+ rendezvous(kidpid, 0);
+ break;
+ }
+
+ for(i=0; i<3; i++)
+ close(pfd[i][1]);
+
+ copyout(c, pfd[1][0], SSH_SMSG_STDOUT_DATA);
+ copyout(c, pfd[2][0], SSH_SMSG_STDERR_DATA);
+ *kidin = pfd[0][0];
+}