shithub: riscv

Download patch

ref: dc8c7bf2b73d608ac2483aee303a51a3507b4c5a
parent: cb1555c7d741fa482c339aa9ac8a44753e2ad296
author: khm <devnull@localhost>
date: Thu Jan 12 11:36:38 EST 2017

ssh: R.I.P.

diff: cannot open a/sys/src/cmd/ssh//null: file does not exist: 'a/sys/src/cmd/ssh//null'
--- a/rc/bin/srvssh
+++ /dev/null
@@ -1,101 +1,0 @@
-#!/bin/rc
-
-# Serve Unix u9fs over SSH
-#
-# Basically, try each of the following until you find one that works:
-#
-#	srvssh unix
-#	srvssh -r unix
-#	srvssh -R unix
-#	srvssh -r -s unix
-#	srvssh -R -s unix
-#
-# and then never look back.  Note that "srvssh unix" should always
-# work.  It's just that if you're talking with certain sshd's, you'll get
-# hit by Nagle's algorithm and need to explore the other flags.
-
-# When using ssh to start u9fs, the only way to turn off
-# Nagle's algorithm (which kills the performance of RPC-based
-# protocols like 9P) is to allocate a pseudo-terminal.  The
-# command ssh -Rmp attempts to allocate a pseudo-terminal and
-# then put it in a transparent mode.  Especially when
-# connected to older SSH daemons, the connection ends up not
-# quite transparent.  To get around this, we explicity set the tty
-# mode on the command line as well.  The hope is that -Rmp makes
-# the connection transparent enough for the Tversion, and the stty
-# command will do the rest.  If -Rmp doesn't make the connection
-# transparent enough for the Tversion (but the stty commands do 
-# make the connection fully transparent) then add "-s 5" to the srv
-# command to tell it to wait 5 seconds before sending the Tversion.
-# That should be enough time for the stty to take effect.
-
-rfork e
-
-fn usage {
-	echo 'usage: srvssh [-R] [-r] [-s] [-u u9fspath] system [srvname [mtpt]]' >[1=2]
-	exit usage
-}
-
-rawhack=''
-sleephack=()
-u9fspath=u9fs
-rawflags=''
-
-while(~ $1 -*){
-	switch($1){
-	case -r
-		rawflags='-Rmp'
-		shift
-	case -R
-		rawflags='-Rmp'
-		rawhack=('stty raw -echo '';''')
-		shift
-	case -s
-		sleephack=(-s 5)
-		shift
-	case -u
-		shift
-		u9fspath=$1
-		shift
-	case -u*
-		u9fspath=`{echo $1 | sed s/-u//}
-		shift
-	case *
-		usage
-	}
-}
-
-if(! ~ $#* 1 2 3)
-	usage
-
-switch($#*){
-case 1
-	srv=$1
-	mtpt=/n/$1
-case 2
-	srv=$2
-	mtpt=/n/$1
-case 3
-	srv=$2
-	mtpt=$3
-}
-
-x=(srv $sleephack -e \
-	'ssh '$rawflags' '$1' '$rawhack' '$u9fspath' -na none -u ''$''USER -l ''$''HOME/u9fs.log' \
-	$srv $mtpt)
-$x
-
-# Sometimes /srv/whatever can be a closed pipe, in which case
-# srv will have been killed for writing to it, without a chance to
-# defend itself.  Rerun it in this case.
-
-ss=$status
-if(~ $ss *'write on closed pipe'*){
-	rm -f /srv/$srv
-	$x
-	ss=$status
-}
-
-if(! ~ $ss '')
-	echo srvssh: $ss >[1=2]
-exit $ss
--- a/sys/man/1/ssh
+++ /dev/null
@@ -1,346 +1,0 @@
-.TH SSH 1
-.SH NAME
-ssh, sshnet, scp, sshserve \- secure login and file copy from/to Unix or Plan 9
-.SH SYNOPSIS
-.B ssh
-[
-.B -CfiImPpRrw
-]
-[
-.B -A
-.I authlist
-]
-[
-.B -c
-.I cipherlist
-]
-[
-.B -[lu]
-.I user
-]
-.RI [ user\fB@ ] host
-[
-.I cmd
-[
-.I args
-\&... ]]
-.PP
-.B sshnet
-[
-.B -A
-.I authlist
-]
-[
-.B -c
-.I cipherlist
-]
-[
-.B -m
-.I mtpt
-]
-[
-.B -s
-.I service
-]
-.RI [ user\fB@ ] host
-.PP
-.B scp
-[host:]file [host:]file
-.br
-.B scp
-[host:]file ... [host:]dir
-.PP
-.B aux/sshserve
-[
-.B -p
-]
-.I address
-.SH DESCRIPTION
-.I Ssh
-allows authenticated login over an encrypted channel to hosts that
-support the ssh protocol (see the RFCs listed below for encryption and
-authentication details).
-.LP
-.I Ssh
-takes the host name of the machine to connect to as its mandatory argument.
-It may be specified as a domain name or an IP address.
-Normally, login is attempted using the user name from /dev/user.
-.PP
-Command-line options are:
-.TP
-.B -C
-force input to be read in cooked mode:
-``line at a time'' with local echo.
-.TP
-.B -f
-enable agent forwarding.
-With this flag,
-.I ssh
-uses SSH's agent forwarding protocol to allow
-programs running on the remote server to
-interact with
-.IR factotum (4)
-to perform RSA authentication.
-.TP
-.B -i
-force interactive mode.
-In interactive mode, 
-.I ssh
-prompts for passwords and confirmations of
-new host keys when necessary.
-(In non-interactive mode, password requests
-are rejected and unrecognized host keys are 
-cause for disconnecting.)
-By default, 
-.I ssh 
-runs in interactive mode only when its 
-input file descriptor is 
-.BR /dev/cons .
-.TP
-.B -I
-force non-interactive mode.
-.TP
-.B -m
-disable the 
-.RB control- \e
-menu, described below.
-.TP
-.B -p
-force pseudoterminal request.
-The
-.I ssh
-protocol, grounded in Unix tradition,
-differentiates between connections
-that request controlling pseudoterminals
-and those that do not.
-By default, 
-.I ssh
-requests a pseudoterminal only when no
-.I command
-is given.
-.TP
-.B -P
-force no pseudoterminal request.
-.TP
-.B -r
-strip carriage returns.
-.TP
-.B -R
-put the allocated pseudoterminal, if any, in raw mode.
-.TP
-.B -w
-notify the remote side whenever the window changes size.
-.TP
-.BR - [ lu ] "\fI user
-specify user name.
-This option is deprecated in favor of the
-.IB user @ hostname
-syntax.
-.TP
-.B "-A\fI authlist
-specify an ordered space-separated list of authentication protocols to try.
-The full set of authentication protocols is
-.B rsa
-(RSA using
-.IR factotum (4)
-to moderate key usage),
-.B password
-(use a password gathered from factotum),
-and
-.B tis
-(challenge-response).
-The default list is all three in that order.
-.TP
-.B "-c\fI cipherlist
-specify an ordered space-separated list of allowed ciphers to use when encrypting the channel.
-The full set of ciphers is
-.B des
-(standard DES),
-.B 3des
-(a somewhat doubtful variation on triple DES),
-.B blowfish
-(Bruce Schneier's Blowfish),
-.B rc4
-(RC4),
-and
-.B none
-(no encryption).
-The default cipher list is 
-.B blowfish
-.B rc4
-.BR 3des .
-.PD
-.PP
-The
-.RB control\- \e
-character is a local escape, as in
-.IR con (1).
-It prompts with
-.BR >>> .
-Legitimate responses to the prompt are
-.TP
-.B q
-Exit.
-.TP
-.B .
-Return from the escape.
-.TP
-.B !cmd
-Run the command with the network connection as its
-standard input and standard output.
-Standard error will go to the screen.
-.TP
-.B r
-Toggle printing of carriage returns.
-.PD
-.LP
-If no command is specified,
-a login session is started on the remote
-host.
-Otherwise, the command is executed with its arguments.
-.LP
-.I Ssh
-establishes a connection with an ssh daemon on the remote host.
-The daemon sends to 
-.I ssh
-its RSA public host key and session key.
-Using these,
-.I ssh
-sends a session key which, presumably, only the
-daemon can decipher.  After this, both sides start encrypting their
-data with this session key.
-.LP
-When the daemon's host key has been received,
-.I ssh
-looks it up in 
-.B $home/lib/keyring
-and in 
-.BR /sys/lib/ssh/keyring .
-If
-the key is found there, and it matches the received key,
-.I ssh
-is satisfied.  If not,
-.I ssh
-reports this and offers to add the key to
-.BR $home/lib/keyring .
-.LP
-Over the encrypted channel,
-.I ssh
-attempts to convince the daemon to accept the call
-using the listed authentication protocols
-(see the
-.B -A
-option above).
-.LP
-The preferred way to authenticate is a
-.IR netkey -style
-challenge/response or via a SecurID token.
-.I Ssh
-users on other systems than Plan 9 should enable \s-2TIS_A\s0uthentication.
-.LP
-When the connection is authenticated, the given command line,
-(by default, a login shell) is executed on the remote host.
-.sp 1
-The SSH protocol allows clients to make outgoing TCP calls via the server.
-.I Sshnet
-establishes an SSH connection and, rather than execute a remote command,
-presents the remote server's TCP stack as a network stack
-(see the discussion of TCP in
-.IR ip (3))
-mounted at
-.I mtpt
-(default
-.BR /net ),
-optionally posting a 9P service
-descriptor for the new file system as
-.IB /srv/ service \fR.
-The
-.B -A
-and
-.B -c
-arguments are as in
-.IR ssh .
-.sp 1
-.I Scp
-uses
-.I ssh
-to copy files from one host to another.  A remote file is identified by
-a host name, a colon and a file name (no spaces).
-.I Scp
-can copy files from remote hosts and to remote hosts.
-.sp 1
-.I Sshserve
-is the server that services
-.I ssh
-calls from remote hosts. 
-The 
-.B -A
-and
-.B -c
-options set valid authentication methods and ciphers
-as in
-.IR ssh ,
-except that there is no
-.B rsa
-authentication method.
-Unlike in
-.IR ssh ,
-the list is not ordered: the server presents a set and the client makes the choice.
-The default sets are
-.B tis
-and
-.B blowfish
-.B rc4
-.BR 3des .
-By default, users start with the namespace defined in
-.BR /lib/namespace .
-Users in group
-.B noworld
-in
-.B /adm/users
-start with the namespace defined in
-.BR /lib/namespace.noworld .
-.I Sshserve
-does not provide the TCP forwarding functionality used
-by
-.IR sshnet ,
-because many Unix clients present
-this capability in an insecure manner.
-.PP
-.I Sshserve
-requires that
-.IR factotum (4)
-hold the host key,
-identified by having attributes
-.B proto=rsa
-.BR service=sshserve .
-To generate a host key:
-.IP
-.EX
-auth/rsagen -t 'service=sshserve' >/mnt/factotum/ctl
-.EE
-.LP
-To extract the public part of the host key in the form
-used by SSH key rings:
-.IP
-.EX
-grep 'service=sshserve' /mnt/factotum/ctl | auth/rsa2ssh
-.EE
-.SH FILES
-.TP
-.B /sys/lib/ssh/keyring
-System key ring file containing public keys for remote ssh clients and servers.
-.TP
-.B /usr/\fIuser\fP/lib/keyring
-Personal key ring file containing public keys for remote ssh clients and
-servers.
-.SH SOURCE
-.B /sys/src/cmd/ssh
-.SH "SEE ALSO"
-.B /lib/rfc/rfc425[0-6]
-.br
-.IR factotum (4),
-.IR authsrv (6),
-.IR rsa (8)
-.SH BUGS
-Only version 1 of the SSH protocol is implemented.
--- a/sys/src/cmd/ssh/agent.c
+++ /dev/null
@@ -1,450 +1,0 @@
-#include "ssh.h"
-#include <bio.h>
-
-typedef struct Key Key;
-struct Key
-{
-	mpint *mod;
-	mpint *ek;
-	char *comment;
-};
-
-typedef struct Achan Achan;
-struct Achan
-{
-	int open;
-	u32int chan;	/* of remote */
-	uchar lbuf[4];
-	uint nlbuf;
-	uint len;
-	uchar *data;
-	int ndata;
-	int needeof;
-	int needclosed;
-};
-
-Achan achan[16];
-
-static char*
-find(char **f, int nf, char *k)
-{
-	int i, len;
-
-	len = strlen(k);
-	for(i=1; i<nf; i++)	/* i=1: f[0] is "key" */
-		if(strncmp(f[i], k, len) == 0 && f[i][len] == '=')
-			return f[i]+len+1;
-	return nil;
-}
-
-static int
-listkeys(Key **kp)
-{
-	Biobuf *b;
-	Key *k;
-	int nk;
-	char *p, *f[20];
-	int nf;
-	mpint *mod, *ek;
-	
-	*kp = nil;
-	if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
-		return -1;
-	
-	k = nil;
-	nk = 0;
-	while((p = Brdline(b, '\n')) != nil){
-		p[Blinelen(b)-1] = '\0';
-		nf = tokenize(p, f, nelem(f));
-		if(nf == 0 || strcmp(f[0], "key") != 0)
-			continue;
-		p = find(f, nf, "proto");
-		if(p == nil || strcmp(p, "rsa") != 0)
-			continue;
-		p = find(f, nf, "n");
-		if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
-			continue;
-		p = find(f, nf, "ek");
-		if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
-			mpfree(mod);
-			continue;
-		}
-		p = find(f, nf, "comment");
-		if(p == nil)
-			p = "";
-		k = erealloc(k, (nk+1)*sizeof(k[0]));
-		k[nk].mod = mod;
-		k[nk].ek = ek;
-		k[nk].comment = emalloc(strlen(p)+1);
-		strcpy(k[nk].comment, p);
-		nk++;
-	}
-	Bterm(b);
-	*kp = k;
-	return nk;	
-}
-
-
-static int
-dorsa(mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
-{
-	int afd;
-	AuthRpc *rpc;
-	mpint *m;
-	char buf[4096], *p;
-	mpint *decr, *unpad;
-
-	USED(exp);
-
-	snprint(buf, sizeof buf, "proto=rsa service=ssh role=client");
-	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
-		debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
-		return -1;
-	}
-	if((rpc = auth_allocrpc(afd)) == nil){
-		debug(DBG_AUTH, "auth_allocrpc: %r\n");
-		close(afd);
-		return -1;
-	}
-	if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
-		debug(DBG_AUTH, "auth_rpc start failed: %r\n");
-	Die:
-		auth_freerpc(rpc);
-		close(afd);
-		return -1;
-	}
-	m = nil;
-	debug(DBG_AUTH, "trying factotum rsa keys\n");
-	while(auth_rpc(rpc, "read", nil, 0) == ARok){
-		debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
-		m = strtomp(rpc->arg, nil, 16, nil);
-		if(mpcmp(m, mod) == 0)
-			break;
-		mpfree(m);
-		m = nil;
-	}
-	if(m == nil)
-		goto Die;
-	mpfree(m);
-	
-	p = mptoa(chal, 16, nil, 0);
-	if(p == nil){
-		debug(DBG_AUTH, "\tmptoa failed: %r\n");
-		goto Die;
-	}
-	if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
-		debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
-		free(p);
-		goto Die;
-	}
-	free(p);
-	if(auth_rpc(rpc, "read", nil, 0) != ARok){
-		debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
-		goto Die;
-	}
-	decr = strtomp(rpc->arg, nil, 16, nil);
-	if(decr == nil){
-		debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg);
-		goto Die;
-	}
-	debug(DBG_AUTH, "\tdecrypted %B\n", decr);
-	unpad = rsaunpad(decr);
-	if(unpad == nil){
-		debug(DBG_AUTH, "\tunpad %B failed\n", decr);
-		mpfree(decr);
-		goto Die;
-	}
-	debug(DBG_AUTH, "\tunpadded %B\n", unpad);
-	mpfree(decr);
-	mptoberjust(unpad, chalbuf, 32);
-	mpfree(unpad);
-	auth_freerpc(rpc);
-	close(afd);
-	return 0;
-}
-
-int
-startagent(Conn *c)
-{
-	int ret;
-	Msg *m;
-
-	m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0);
-	sendmsg(m);
-
-	m = recvmsg(c, -1);
-	switch(m->type){
-	case SSH_SMSG_SUCCESS:
-		debug(DBG_AUTH, "agent allocated\n");
-		ret = 0;
-		break;
-	case SSH_SMSG_FAILURE:
-		debug(DBG_AUTH, "agent failed to allocate\n");
-		ret = -1;
-		break;
-	default:
-		badmsg(m, 0);
-		ret = -1;
-		break;
-	}
-	free(m);
-	return ret;
-}
-
-void handlefullmsg(Conn*, Achan*);
-
-void
-handleagentmsg(Msg *m)
-{
-	u32int chan, len;
-	int n;
-	Achan *a;
-
-	assert(m->type == SSH_MSG_CHANNEL_DATA);
-
-	debug(DBG_AUTH, "agent data\n");
-	debug(DBG_AUTH, "\t%.*H\n", (int)(m->ep - m->rp), m->rp);
-	chan = getlong(m);
-	len = getlong(m);
-	if(m->rp+len != m->ep)
-		sysfatal("got bad channel data");
-
-	if(chan >= nelem(achan))
-		error("bad channel in agent request");
-
-	a = &achan[chan];
-
-	while(m->rp < m->ep){
-		if(a->nlbuf < 4){
-			a->lbuf[a->nlbuf++] = getbyte(m);
-			if(a->nlbuf == 4){
-				a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
-				a->data = erealloc(a->data, a->len);
-				a->ndata = 0;
-			}
-			continue;
-		}
-		if(a->ndata < a->len){
-			n = a->len - a->ndata;
-			if(n > m->ep - m->rp)
-				n = m->ep - m->rp;
-			memmove(a->data+a->ndata, getbytes(m, n), n);
-			a->ndata += n;
-		}
-		if(a->ndata == a->len){
-			handlefullmsg(m->c, a);
-			a->nlbuf = 0;
-		}
-	}
-}
-
-void
-handlefullmsg(Conn *c, Achan *a)
-{
-	int i;
-	u32int chan, len, n, rt;
-	uchar type;
-	Msg *m, mm;
-	Msg *r;
-	Key *k;
-	int nk;
-	mpint *mod, *ek, *chal;
-	uchar sessid[16];
-	uchar chalbuf[32];
-	uchar digest[16];
-	DigestState *s;
-	static int first;
-
-	assert(a->len == a->ndata);
-
-	chan = a->chan;
-	mm.rp = a->data;
-	mm.ep = a->data+a->ndata;
-	mm.c = c;
-	m = &mm;
-
-	type = getbyte(m);
-
-	if(first == 0){
-		first++;
-		fmtinstall('H', encodefmt);
-	}
-
-	switch(type){
-	default:
-		debug(DBG_AUTH, "unknown msg type\n");
-	Failure:
-		debug(DBG_AUTH, "agent sending failure\n");
-		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
-		putlong(r, chan);
-		putlong(r, 5);
-		putlong(r, 1);
-		putbyte(r, SSH_AGENT_FAILURE);
-		sendmsg(r);
-		return;
-
-	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
-		debug(DBG_AUTH, "agent request identities\n");
-		nk = listkeys(&k);
-		if(nk < 0)
-			goto Failure;
-		len = 1+4;	/* type, nk */
-		for(i=0; i<nk; i++){
-			len += 4;
-			len += 2+(mpsignif(k[i].ek)+7)/8;
-			len += 2+(mpsignif(k[i].mod)+7)/8;
-			len += 4+strlen(k[i].comment);
-		}
-		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
-		putlong(r, chan);
-		putlong(r, len+4);
-		putlong(r, len);
-		putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
-		putlong(r, nk);
-		for(i=0; i<nk; i++){
-			debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
-			putlong(r, mpsignif(k[i].mod));
-			putmpint(r, k[i].ek);
-			putmpint(r, k[i].mod);
-			putstring(r, k[i].comment);
-			mpfree(k[i].ek);
-			mpfree(k[i].mod);
-			free(k[i].comment);
-		}
-		free(k);
-		sendmsg(r);
-		break;
-
-	case SSH_AGENTC_RSA_CHALLENGE:
-		n = getlong(m);
-		USED(n);	/* number of bits in key; who cares? */
-		ek = getmpint(m);
-		mod = getmpint(m);
-		chal = getmpint(m);
-		memmove(sessid, getbytes(m, 16), 16);
-		rt = getlong(m);
-		debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
-			ek, mod, chal, rt, m->rp, m->ep);
-		if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
-			mpfree(ek);
-			mpfree(mod);
-			mpfree(chal);
-			goto Failure;
-		}
-		s = md5(chalbuf, 32, nil, nil);
-		md5(sessid, 16, digest, s);
-		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
-		putlong(r, chan);
-		putlong(r, 4+16+1);
-		putlong(r, 16+1);
-		putbyte(r, SSH_AGENT_RSA_RESPONSE);
-		putbytes(r, digest, 16);
-		debug(DBG_AUTH, "digest %.16H\n", digest);
-		sendmsg(r);
-		mpfree(ek);
-		mpfree(mod);
-		mpfree(chal);
-		return;
-
-	case SSH_AGENTC_ADD_RSA_IDENTITY:
-		goto Failure;
-/*
-		n = getlong(m);
-		pubmod = getmpint(m);
-		pubexp = getmpint(m);
-		privexp = getmpint(m);
-		pinversemodq = getmpint(m);
-		p = getmpint(m);
-		q = getmpint(m);
-		comment = getstring(m);
-		add to factotum;
-		send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
-*/
-
-	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
-		goto Failure;
-/*
-		n = getlong(m);
-		pubmod = getmpint(m);
-		pubexp = getmpint(m);
-		tell factotum to del key
-		send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
-*/
-	}
-}
-
-void
-handleagentopen(Msg *m)
-{
-	int i;
-	u32int remote;
-
-	assert(m->type == SSH_SMSG_AGENT_OPEN);
-	remote = getlong(m);
-	debug(DBG_AUTH, "agent open %d\n", remote);
-
-	for(i=0; i<nelem(achan); i++)
-		if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
-			break;
-	if(i == nelem(achan)){
-		m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
-		putlong(m, remote);
-		sendmsg(m);
-		return;
-	}
-
-	debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
-	achan[i].open = 1;
-	achan[i].needeof = 1;
-	achan[i].needclosed = 1;
-	achan[i].nlbuf = 0;
-	achan[i].chan = remote;
-	m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
-	putlong(m, remote);
-	putlong(m, i);
-	sendmsg(m);
-}
-
-void
-handleagentieof(Msg *m)
-{
-	u32int local;
-
-	assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
-	local = getlong(m);
-	debug(DBG_AUTH, "agent close %d\n", local);
-	if(local < nelem(achan)){
-		debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
-		achan[local].open = 0;
-/*
-		m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
-		putlong(m, achan[local].chan);
-		sendmsg(m);
-*/
-		if(achan[local].needeof){
-			achan[local].needeof = 0;
-			m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
-			putlong(m, achan[local].chan);
-			sendmsg(m);
-		}
-	}
-}
-
-void
-handleagentoclose(Msg *m)
-{
-	u32int local;
-
-	assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
-	local = getlong(m);
-	debug(DBG_AUTH, "agent close %d\n", local);
-	if(local < nelem(achan)){
-		debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
-		if(achan[local].needclosed){
-			achan[local].needclosed = 0;
-			m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
-			putlong(m, achan[local].chan);
-			sendmsg(m);
-		}
-	}
-}
--- a/sys/src/cmd/ssh/authpasswd.c
+++ /dev/null
@@ -1,38 +1,0 @@
-#include "ssh.h"
-
-static int
-authpasswordfn(Conn *c)
-{
-	Msg *m;
-	UserPasswd *up;
-
-	up = auth_getuserpasswd(c->interactive ? auth_getkey : nil, "proto=pass service=ssh server=%q user=%q", c->host, c->user);
-	if(up == nil){
-		debug(DBG_AUTH, "getuserpasswd returned nothing (interactive=%d)\n", c->interactive);
-		return -1;
-	}
-
-	debug(DBG_AUTH, "try using password from factotum\n");
-	m = allocmsg(c, SSH_CMSG_AUTH_PASSWORD, 4+strlen(up->passwd));
-	putstring(m, up->passwd);
-	sendmsg(m);
-
-	m = recvmsg(c, -1);
-	switch(m->type){
-	default:
-		badmsg(m, 0);
-	case SSH_SMSG_SUCCESS:
-		free(m);
-		return 0;
-	case SSH_SMSG_FAILURE:
-		free(m);
-		return -1;
-	}
-}
-
-Auth authpassword =
-{
-	SSH_AUTH_PASSWORD,
-	"password",
-	authpasswordfn,
-};
--- a/sys/src/cmd/ssh/authrsa.c
+++ /dev/null
@@ -1,113 +1,0 @@
-#include "ssh.h"
-
-static int
-authrsafn(Conn *c)
-{
-	uchar chalbuf[32+SESSIDLEN], response[MD5dlen];
-	char *s, *p;
-	int afd, ret;
-	AuthRpc *rpc;
-	Msg *m;
-	mpint *chal, *decr, *unpad, *mod;
-
-	debug(DBG_AUTH, "rsa!\n");
-
-	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
-		debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
-		return -1;
-	}
-	if((rpc = auth_allocrpc(afd)) == nil){
-		debug(DBG_AUTH, "auth_allocrpc: %r\n");
-		close(afd);
-		return -1;
-	}
-	s = "proto=rsa role=client";
-	if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
-		debug(DBG_AUTH, "auth_rpc start %s failed: %r\n", s);
-		auth_freerpc(rpc);
-		close(afd);
-		return -1;
-	}
-
-	ret = -1;
-	debug(DBG_AUTH, "trying factotum rsa keys\n");
-	while(auth_rpc(rpc, "read", nil, 0) == ARok){
-		debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
-		mod = strtomp(rpc->arg, nil, 16, nil);
-		m = allocmsg(c, SSH_CMSG_AUTH_RSA, 16+(mpsignif(mod)+7/8));
-		putmpint(m, mod);
-		sendmsg(m);
-		mpfree(mod);
-		m = recvmsg(c, -1);
-		switch(m->type){
-		case SSH_SMSG_FAILURE:
-			debug(DBG_AUTH, "\tnot accepted %s\n", (char*)rpc->arg);
-			free(m);
-			continue;
-		default:
-			badmsg(m, 0);
-		case SSH_SMSG_AUTH_RSA_CHALLENGE:
-			break;
-		}
-		chal = getmpint(m);
-		debug(DBG_AUTH, "\tgot challenge %B\n", chal);
-		free(m);
-		p = mptoa(chal, 16, nil, 0);
-		mpfree(chal);
-		if(p == nil){
-			debug(DBG_AUTH, "\tmptoa failed: %r\n");
-			unpad = mpnew(0);
-			goto Keepgoing;
-		}
-		if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
-			debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
-			free(p);
-			unpad = mpnew(0);	/* it will fail, we'll go round again */
-			goto Keepgoing;
-		}
-		free(p);
-		if(auth_rpc(rpc, "read", nil, 0) != ARok){
-			debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
-			unpad = mpnew(0);
-			goto Keepgoing;
-		}
-		decr = strtomp(rpc->arg, nil, 16, nil);
-		debug(DBG_AUTH, "\tdecrypted %B\n", decr);
-		unpad = rsaunpad(decr);
-		debug(DBG_AUTH, "\tunpadded %B\n", unpad);
-		mpfree(decr);
-	Keepgoing:
-		mptoberjust(unpad, chalbuf, 32);
-		mpfree(unpad);
-		debug(DBG_AUTH, "\trjusted %.*H\n", 32, chalbuf);
-		memmove(chalbuf+32, c->sessid, SESSIDLEN);
-		debug(DBG_AUTH, "\tappend sesskey %.*H\n", 32, chalbuf);
-		md5(chalbuf, 32+SESSIDLEN, response, nil);
-		m = allocmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE, MD5dlen);
-		putbytes(m, response, MD5dlen);
-		sendmsg(m);
-
-		m = recvmsg(c, -1);
-		switch(m->type){
-		case SSH_SMSG_FAILURE:
-			free(m);
-			continue;
-		default:
-			badmsg(m, 0);
-		case SSH_SMSG_SUCCESS:
-			break;
-		}
-		ret = 0;
-		break;
-	}
-	auth_freerpc(rpc);
-	close(afd);
-	return ret;
-}
-
-Auth authrsa =
-{
-	SSH_AUTH_RSA,
-	"rsa",
-	authrsafn,
-};
--- a/sys/src/cmd/ssh/authsrvpasswd.c
+++ /dev/null
@@ -1,22 +1,0 @@
-#include "ssh.h"
-
-static AuthInfo*
-authsrvpasswordfn(Conn *c, Msg *m)
-{
-	char *pass;
-	AuthInfo *ai;
-
-	pass = getstring(m);
-	ai = auth_userpasswd(c->user, pass);
-	free(m);
-	return ai;
-}
-
-Authsrv authsrvpassword =
-{
-	SSH_AUTH_PASSWORD,
-	"password",
-	SSH_CMSG_AUTH_PASSWORD,
-	authsrvpasswordfn,
-};
-
--- a/sys/src/cmd/ssh/authsrvtis.c
+++ /dev/null
@@ -1,52 +1,0 @@
-#include "ssh.h"
-
-static AuthInfo*
-authsrvtisfn(Conn *conn, Msg *m)
-{
-	char *s;
-	AuthInfo *ai;
-	Chalstate *c;
-
-	free(m);
-	if((c = auth_challenge("proto=p9cr user=%q role=server", conn->user)) == nil){
-		sshlog("auth_challenge failed for %s", conn->user);
-		return nil;
-	}
-	s = smprint("Challenge: %s\nResponse: ", c->chal);
-	if(s == nil){
-		auth_freechal(c);
-		return nil;
-	}
-	m = allocmsg(conn, SSH_SMSG_AUTH_TIS_CHALLENGE, 4+strlen(s));
-	putstring(m, s);
-	sendmsg(m);
-	free(s);
-
-	m = recvmsg(conn, 0);
-	if(m == nil){
-		auth_freechal(c);
-		return nil;
-	}
-	if(m->type != SSH_CMSG_AUTH_TIS_RESPONSE){
-		/*
-		 * apparently you can just give up on
-		 * this protocol and start a new one.
-		 */
-		unrecvmsg(conn, m);
-		return nil;
-	}
-
-	c->resp = getstring(m);
-	c->nresp = strlen(c->resp);
-	ai = auth_response(c);
-	auth_freechal(c);
-	return ai;
-}
-
-Authsrv authsrvtis = 
-{
-	SSH_AUTH_TIS,
-	"tis",
-	SSH_CMSG_AUTH_TIS,
-	authsrvtisfn,
-};
--- a/sys/src/cmd/ssh/authtis.c
+++ /dev/null
@@ -1,65 +1,0 @@
-#include "ssh.h"
-
-static int
-authtisfn(Conn *c)
-{
-	int fd, n;
-	char *chal, resp[256];
-	Msg *m;
-
-	if(!c->interactive)
-		return -1;
-
-	debug(DBG_AUTH, "try TIS\n");
-	sendmsg(allocmsg(c, SSH_CMSG_AUTH_TIS, 0));
-
-	m = recvmsg(c, -1);
-	switch(m->type){
-	default:
-		badmsg(m, SSH_SMSG_AUTH_TIS_CHALLENGE);
-	case SSH_SMSG_FAILURE:
-		free(m);
-		return -1;
-	case SSH_SMSG_AUTH_TIS_CHALLENGE:
-		break;
-	}
-
-	chal = getstring(m);
-	free(m);
-
-	if((fd = open("/dev/cons", ORDWR)) < 0)
-		error("can't open console");
-
-	fprint(fd, "TIS Authentication\n%s", chal);
-	n = read(fd, resp, sizeof resp-1);
-	if(n < 0)
-		resp[0] = '\0';
-	else
-		resp[n] = '\0';
-
-	if(resp[0] == 0 || resp[0] == '\n')
-		return -1;
-
-	m = allocmsg(c, SSH_CMSG_AUTH_TIS_RESPONSE, 4+strlen(resp));
-	putstring(m, resp);
-	sendmsg(m);
-	
-	m = recvmsg(c, -1);
-	switch(m->type){
-	default:
-		badmsg(m, 0);
-	case SSH_SMSG_SUCCESS:
-		free(m);
-		return 0;
-	case SSH_SMSG_FAILURE:
-		free(m);
-		return -1;
-	}
-}
-
-Auth authtis =
-{
-	SSH_AUTH_TIS,
-	"tis",
-	authtisfn,
-};
--- a/sys/src/cmd/ssh/cipher3des.c
+++ /dev/null
@@ -1,47 +1,0 @@
-#include "ssh.h"
-
-struct CipherState
-{
-	DESstate enc3des[3];
-	DESstate dec3des[3];
-};
-
-static CipherState*
-init3des(Conn *c, int)
-{
-	int i;
-	CipherState *cs;
-
-	cs = emalloc(sizeof(CipherState));
-	for(i=0; i<3; i++){
-		setupDESstate(&cs->enc3des[i], c->sesskey+8*i, nil);
-		setupDESstate(&cs->dec3des[i], c->sesskey+8*i, nil);
-	}
-	return cs;
-}
-
-static void
-encrypt3des(CipherState *cs, uchar *buf, int nbuf)
-{
-	desCBCencrypt(buf, nbuf, &cs->enc3des[0]);
-	desCBCdecrypt(buf, nbuf, &cs->enc3des[1]);
-	desCBCencrypt(buf, nbuf, &cs->enc3des[2]);
-}
-
-static void
-decrypt3des(CipherState *cs, uchar *buf, int nbuf)
-{
-	desCBCdecrypt(buf, nbuf, &cs->dec3des[2]);
-	desCBCencrypt(buf, nbuf, &cs->dec3des[1]);
-	desCBCdecrypt(buf, nbuf, &cs->dec3des[0]);
-}
-
-Cipher cipher3des =
-{
-	SSH_CIPHER_3DES,
-	"3des",
-	init3des,
-	encrypt3des,
-	decrypt3des,
-};
-
--- a/sys/src/cmd/ssh/cipherblowfish.c
+++ /dev/null
@@ -1,40 +1,0 @@
-#include "ssh.h"
-
-struct CipherState
-{
-	BFstate enc;
-	BFstate dec;
-};
-
-static CipherState*
-initblowfish(Conn *c, int)
-{
-	CipherState *cs;
-
-	cs = emalloc(sizeof(CipherState));
-	setupBFstate(&cs->enc, c->sesskey, SESSKEYLEN, nil);
-	setupBFstate(&cs->dec, c->sesskey, SESSKEYLEN, nil);
-	return cs;
-}
-
-static void
-encryptblowfish(CipherState *cs, uchar *buf, int nbuf)
-{
-	bfCBCencrypt(buf, nbuf, &cs->enc);
-}
-
-static void
-decryptblowfish(CipherState *cs, uchar *buf, int nbuf)
-{
-	bfCBCdecrypt(buf, nbuf, &cs->dec);
-}
-
-Cipher cipherblowfish = 
-{
-	SSH_CIPHER_BLOWFISH,
-	"blowfish",
-	initblowfish,
-	encryptblowfish,
-	decryptblowfish,
-};
-
--- a/sys/src/cmd/ssh/cipherdes.c
+++ /dev/null
@@ -1,40 +1,0 @@
-#include "ssh.h"
-
-struct CipherState
-{
-	DESstate enc;
-	DESstate dec;
-};
-
-static CipherState*
-initdes(Conn *c, int)
-{
-	CipherState *cs;
-
-	cs = emalloc(sizeof(CipherState));
-	setupDESstate(&cs->enc, c->sesskey, nil);
-	setupDESstate(&cs->dec, c->sesskey, nil);
-	return cs;
-}
-
-static void
-encryptdes(CipherState *cs, uchar *buf, int nbuf)
-{
-	desCBCencrypt(buf, nbuf, &cs->enc);
-}
-
-static void
-decryptdes(CipherState *cs, uchar *buf, int nbuf)
-{
-	desCBCdecrypt(buf, nbuf, &cs->dec);
-}
-
-Cipher cipherdes =
-{
-	SSH_CIPHER_DES,
-	"des",
-	initdes,
-	encryptdes,
-	decryptdes,
-};
-
--- a/sys/src/cmd/ssh/ciphernone.c
+++ /dev/null
@@ -1,28 +1,0 @@
-#include "ssh.h"
-
-static CipherState*
-initnone(Conn*, int)
-{
-	/* must be non-nil */
-	return (CipherState*)~0;
-}
-
-static void
-encryptnone(CipherState*, uchar*, int)
-{
-}
-
-static void
-decryptnone(CipherState*, uchar*, int)
-{
-}
-
-Cipher ciphernone =
-{
-	SSH_CIPHER_NONE,
-	"none",
-	initnone,
-	encryptnone,
-	decryptnone,
-};
-
--- a/sys/src/cmd/ssh/cipherrc4.c
+++ /dev/null
@@ -1,45 +1,0 @@
-#include "ssh.h"
-
-struct CipherState
-{
-	RC4state enc;
-	RC4state dec;
-};
-
-static CipherState*
-initrc4(Conn *c, int isserver)
-{
-	CipherState *cs;
-
-	cs = emalloc(sizeof(CipherState));
-	if(isserver){
-		setupRC4state(&cs->enc, c->sesskey, 16);
-		setupRC4state(&cs->dec, c->sesskey+16, 16);
-	}else{
-		setupRC4state(&cs->dec, c->sesskey, 16);
-		setupRC4state(&cs->enc, c->sesskey+16, 16);
-	}
-	return cs;
-}
-
-static void
-encryptrc4(CipherState *cs, uchar *buf, int nbuf)
-{
-	rc4(&cs->enc, buf, nbuf);
-}
-
-static void
-decryptrc4(CipherState *cs, uchar *buf, int nbuf)
-{
-	rc4(&cs->dec, buf, nbuf);
-}
-
-Cipher cipherrc4 =
-{
-	SSH_CIPHER_RC4,
-	"rc4",
-	initrc4,
-	encryptrc4,
-	decryptrc4,
-};
-
--- a/sys/src/cmd/ssh/ciphertwiddle.c
+++ /dev/null
@@ -1,28 +1,0 @@
-#include "ssh.h"
-
-static CipherState*
-inittwiddle(Conn *c, int)
-{
-	/* must be non-nil */
-	fprint(2, "twiddle key is %.*H\n", SESSKEYLEN, c->sesskey);
-	return (CipherState*)~0;
-}
-
-static void
-twiddle(CipherState*, uchar *buf, int n)
-{
-	int i;
-
-	for(i=0; i<n; i++)
-		buf[i] ^= 0xFF;
-}
-
-Cipher ciphertwiddle =
-{
-	SSH_CIPHER_TWIDDLE,
-	"twiddle",
-	inittwiddle,
-	twiddle,
-	twiddle,
-};
-
--- a/sys/src/cmd/ssh/cmsg.c
+++ /dev/null
@@ -1,376 +1,0 @@
-#include "ssh.h"
-
-static void
-recv_ssh_smsg_public_key(Conn *c)
-{
-	Msg *m;
-
-	m = recvmsg(c, SSH_SMSG_PUBLIC_KEY);
-	memmove(c->cookie, getbytes(m, COOKIELEN), COOKIELEN);
-	c->serverkey = getRSApub(m);
-	c->hostkey = getRSApub(m);
-	c->flags = getlong(m);
-	c->ciphermask = getlong(m);
-	c->authmask = getlong(m);
-	free(m);
-}
-
-static void
-send_ssh_cmsg_session_key(Conn *c)
-{
-	int i, n, buflen, serverkeylen, hostkeylen;
-	mpint *b;
-	uchar *buf;
-	Msg *m;
-	RSApub *ksmall, *kbig;
-
-	m = allocmsg(c, SSH_CMSG_SESSION_KEY, 2048);
-	putbyte(m, c->cipher->id);
-	putbytes(m, c->cookie, COOKIELEN);
-
-	serverkeylen = mpsignif(c->serverkey->n);
-	hostkeylen = mpsignif(c->hostkey->n);
-	ksmall = kbig = nil;
-	if(serverkeylen+128 <= hostkeylen){
-		ksmall = c->serverkey;
-		kbig = c->hostkey;
-	}else if(hostkeylen+128 <= serverkeylen){
-		ksmall = c->hostkey;
-		kbig = c->serverkey;
-	}else
-		error("server session and host keys do not differ by at least 128 bits");
-	
-	buflen = (mpsignif(kbig->n)+7)/8;
-	buf = emalloc(buflen);
-
-	debug(DBG_CRYPTO, "session key is %.*H\n", SESSKEYLEN, c->sesskey);
-	memmove(buf, c->sesskey, SESSKEYLEN);
-	for(i = 0; i < SESSIDLEN; i++)
-		buf[i] ^= c->sessid[i];
-	debug(DBG_CRYPTO, "munged session key is %.*H\n", SESSKEYLEN, buf);
-
-	b = rsaencryptbuf(ksmall, buf, SESSKEYLEN);
-	n = (mpsignif(ksmall->n)+7) / 8;
-	mptoberjust(b, buf, n);
-	mpfree(b);
-	debug(DBG_CRYPTO, "encrypted with ksmall is %.*H\n", n, buf);
-
-	b = rsaencryptbuf(kbig, buf, n);
-	putmpint(m, b);
-	debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b);
-	mpfree(b);
-
-	memset(buf, 0, buflen);
-	free(buf);
-
-	putlong(m, c->flags);
-	sendmsg(m);
-}
-
-static int
-authuser(Conn *c)
-{
-	int i;
-	Msg *m;
-
-	m = allocmsg(c, SSH_CMSG_USER, 4+strlen(c->user));
-	putstring(m, c->user);
-	sendmsg(m);
-
-	m = recvmsg(c, -1);
-	switch(m->type){
-	case SSH_SMSG_SUCCESS:
-		free(m);
-		return 0;
-	case SSH_SMSG_FAILURE:
-		free(m);
-		break;
-	default:
-		badmsg(m, 0);
-	}
-
-	for(i=0; i<c->nokauth; i++){
-		debug(DBG_AUTH, "authmask %#lux, consider %s (%#x)\n",
-			c->authmask, c->okauth[i]->name, 1<<c->okauth[i]->id);
-		if(c->authmask & (1<<c->okauth[i]->id))
-			if((*c->okauth[i]->fn)(c) == 0)
-				return 0;
-	}
-
-	debug(DBG_AUTH, "no auth methods worked; (authmask=%#lux)\n", c->authmask);
-	return -1;
-}
-
-static char
-ask(Conn *c, char *answers, char *question)
-{
-	int fd;
-	char buf[256];
-
-	if(!c->interactive)
-		return answers[0];
-
-	if((fd = open("/dev/cons", ORDWR)) < 0)
-		return answers[0];
-
-	fprint(fd, "%s", question);
-	if(read(fd, buf, 256) <= 0 || buf[0]=='\n'){
-		close(fd);
-		return answers[0];
-	}
-	close(fd);
-	return buf[0];
-}
-static void
-checkkey(Conn *c)
-{
-	char *home, *keyfile;
-
-	debug(DBG_CRYPTO, "checking key %B %B\n", c->hostkey->n, c->hostkey->ek);
-	switch(findkey("/sys/lib/ssh/keyring", c->aliases, c->hostkey)){
-	default:
-		abort();
-	case KeyOk:
-		return;
-	case KeyWrong:
-		fprint(2, "server presented public key different than expected\n");
-		fprint(2, "(expected key in /sys/lib/ssh/keyring).  will not continue.\n");
-		error("bad server key");
-
-	case NoKey:
-	case NoKeyFile:
-		break;
-	}
-
-	home = getenv("home");
-	if(home == nil){
-		fprint(2, "server %s not on keyring; will not continue.\n", c->host);
-		error("bad server key");
-	}
-	
-	keyfile = smprint("%s/lib/keyring", home);
-	if(keyfile == nil)
-		error("out of memory");
-
-	switch(findkey(keyfile, c->aliases, c->hostkey)){
-	default:
-		abort();
-	case KeyOk:
-		return;
-	case KeyWrong:
-		fprint(2, "server %s presented public key different than expected\n", c->host);
-		fprint(2, "(expected key in %s).  will not continue.\n", keyfile);
-		fprint(2, "this could be a man-in-the-middle attack.\n");
-		switch(ask(c, "eri", "replace key in keyfile (r), continue without replacing key (c), or exit (e) [e]")){
-		case 'e':
-			error("bad key");
-		case 'r':
-			if(replacekey(keyfile, c->aliases, c->hostkey) < 0)
-				error("replacekey: %r");
-			break;
-		case 'c':
-			break;
-		}
-		return;
-	case NoKey:
-	case NoKeyFile:
-		fprint(2, "server %s not on keyring.\n", c->host);
-		switch(ask(c, "eac", "add key to keyfile (a), continue without adding key (c), or exit (e) [e]")){
-		case 'e':
-			error("bad key");
-		case 'a':
-			if(appendkey(keyfile, c->aliases, c->hostkey) < 0)
-				error("appendkey: %r");
-			break;
-		case 'c':
-			break;
-		}
-		return;
-	}
-}
-
-void
-sshclienthandshake(Conn *c)
-{
-	char buf[128], *p;
-	int i;
-	Msg *m;
-
-	/* receive id string */
-	if(readstrnl(c->fd[0], buf, sizeof buf) < 0)
-		error("reading server version: %r");
-
-	/* id string is "SSH-m.n-comment".  We need m=1, n>=5. */
-	if(strncmp(buf, "SSH-", 4) != 0
-	|| strtol(buf+4, &p, 10) != 1
-	|| *p != '.'
-	|| strtol(p+1, &p, 10) < 5
-	|| *p != '-')
-		error("protocol mismatch; got %s, need SSH-1.x for x>=5", buf);
-
-	/* send id string */
-	fprint(c->fd[1], "SSH-1.5-Plan 9\n");
-
-	recv_ssh_smsg_public_key(c);
-	checkkey(c);
-
-	for(i=0; i<SESSKEYLEN; i++)
-		c->sesskey[i] = fastrand();
-	c->cipher = nil;
-	for(i=0; i<c->nokcipher; i++)
-		if((1<<c->okcipher[i]->id) & c->ciphermask){
-			c->cipher = c->okcipher[i];
-			break;
-		}
-	if(c->cipher == nil)
-		error("can't agree on ciphers: remote side supports %#lux", c->ciphermask);
-
-	calcsessid(c);
-
-	send_ssh_cmsg_session_key(c);
-
-	c->cstate = (*c->cipher->init)(c, 0);		/* turns on encryption */
-	m = recvmsg(c, SSH_SMSG_SUCCESS);
-	free(m);
-	
-	if(authuser(c) < 0)
-		error("client authentication failed");
-}
-
-static int
-intgetenv(char *name, int def)
-{
-	char *s;
-	int n, val;
-
-	val = def;
-	if((s = getenv(name))!=nil){
-		if((n=atoi(s)) > 0)
-			val = n;
-		free(s);
-	}
-	return val;
-}
-
-/*
- * assumes that if you care, you're running under vt
- * and therefore these are set.
- */
-int
-readgeom(int *nrow, int *ncol, int *width, int *height)
-{
-	static int fd = -1;
-	char buf[64];
-
-	if(fd < 0 && (fd = open("/dev/wctl", OREAD)) < 0)
-		return -1;
-	/* wait for event, but don't care what it says */
-	if(read(fd, buf, sizeof buf) < 0)
-		return -1;
-	*nrow = intgetenv("LINES", 24);
-	*ncol = intgetenv("COLS", 80);
-	*width = intgetenv("XPIXELS", 640);
-	*height = intgetenv("YPIXELS", 480);
-	return 0;
-}
-
-void
-sendwindowsize(Conn *c, int nrow, int ncol, int width, int height)
-{
-	Msg *m;
-
-	m = allocmsg(c, SSH_CMSG_WINDOW_SIZE, 4*4);
-	putlong(m, nrow);
-	putlong(m, ncol);
-	putlong(m, width);
-	putlong(m, height);
-	sendmsg(m);
-}
-
-/*
- * In each option line, the first byte is the option number
- * and the second is either a boolean bit or actually an
- * ASCII code.
- */
-static uchar ptyopt[] =
-{
-	0x01, 0x7F,	/* interrupt = DEL */
-	0x02, 0x11,	/* quit = ^Q */
-	0x03, 0x08,	/* backspace = ^H */
-	0x04, 0x15,	/* line kill = ^U */
-	0x05, 0x04,	/* EOF = ^D */
-	0x20, 0x00,	/* don't strip high bit */
-	0x48, 0x01,	/* give us CRs */
-
-	0x00,		/* end options */
-};
-
-static uchar rawptyopt[] = 
-{
-	30,	0,		/* ignpar */
-	31,	0,		/* parmrk */
-	32,	0,		/* inpck */
-	33,	0,		/* istrip */
-	34,	0,		/* inlcr */
-	35,	0,		/* igncr */
-	36,	0,		/* icnrl */
-	37,	0,		/* iuclc */
-	38,	0,		/* ixon */
-	39,	1,		/* ixany */
-	40,	0,		/* ixoff */
-	41,	0,		/* imaxbel */
-
-	50,	0,		/* isig: intr, quit, susp processing */
-	51,	0,		/* icanon: erase and kill processing */
-	52,	0,		/* xcase */
-
-	53,	0,		/* echo */
-
-	57,	0,		/* noflsh */
-	58,	0,		/* tostop */
-	59,	0,		/* iexten: impl defined control chars */
-
-	70,	0,		/* opost */
-
-	0x00,
-};
-
-void
-requestpty(Conn *c)
-{
-	char *term;
-	int nrow, ncol, width, height;
-	Msg *m;
-
-	m = allocmsg(c, SSH_CMSG_REQUEST_PTY, 1024);
-	if((term = getenv("TERM")) == nil)
-		term = "9term";
-	putstring(m, term);
-
-	readgeom(&nrow, &ncol, &width, &height);
-	putlong(m, nrow);	/* characters */
-	putlong(m, ncol);
-	putlong(m, width);	/* pixels */
-	putlong(m, height);
-
-	if(rawhack)
-		putbytes(m, rawptyopt, sizeof rawptyopt);
-	else
-		putbytes(m, ptyopt, sizeof ptyopt);
-
-	sendmsg(m);
-
-	m = recvmsg(c, 0);
-	switch(m->type){
-	case SSH_SMSG_SUCCESS:
-		debug(DBG_IO, "PTY allocated\n");
-		break;
-	case SSH_SMSG_FAILURE:
-		debug(DBG_IO, "PTY allocation failed\n");
-		break;
-	default:
-		badmsg(m, 0);
-	}
-	free(m);
-}
-
--- a/sys/src/cmd/ssh/mkfile
+++ /dev/null
@@ -1,78 +1,0 @@
-</$objtype/mkfile
-
-HFILES=ssh.h
-
-TARG=\
-	scp\
-	ssh\
-	sshnet\
-	sshserve\
-
-AUTHOFILES=\
-	authpasswd.$O\
-	authrsa.$O\
-	authtis.$O\
-
-AUTHSRVOFILES=\
-	authsrvpasswd.$O\
-	authsrvtis.$O\
-
-CIPHEROFILES=\
-	cipher3des.$O\
-	cipherblowfish.$O\
-	cipherdes.$O\
-	ciphernone.$O\
-	cipherrc4.$O\
-	ciphertwiddle.$O\
-
-OFILES=\
-	msg.$O\
-	util.$O\
-
-BIN=/$objtype/bin
-
-UPDATE=\
-	mkfile\
-	agent.c\
-	cmsg.c\
-	smsg.c\
-	pubkey.c\
-	$HFILES\
-	${OFILES:%.$O=%.c}\
-	${AUTHOFILES:%.$O=%.c}\
-	${AUTHSRVOFILES:%.$O=%.c}\
-	${CIPHEROFILES:%.$O=%.c}\
-	${TARG:%=%.c}\
-
-</sys/src/cmd/mkmany
-
-$O.ssh: \
-	$AUTHOFILES\
-	$CIPHEROFILES\
-	agent.$O\
-	cmsg.$O\
-	pubkey.$O\
-
-$O.sshserve: \
-	$AUTHSRVOFILES\
-	$CIPHEROFILES\
-	smsg.$O\
-
-$O.sshnet: \
-	$AUTHOFILES\
-	$CIPHEROFILES\
-	cmsg.$O\
-	pubkey.$O\
-
-$BIN/sshserve:VQ: $BIN/aux/sshserve
-	;
-
-$BIN/aux/sshserve: $O.sshserve
-	cp $O.sshserve $BIN/aux/sshserve
-
-$BIN/aux/ssh_genkey: $O.ssh_genkey
-	cp $O.ssh_genkey $BIN/aux/ssh_genkey
-
-sshserve.safeinstall:
-	test -e $BIN/aux/sshserve && mv $BIN/aux/sshserve $BIN/aux/_sshserve
-	mk sshserve.install
--- a/sys/src/cmd/ssh/msg.c
+++ /dev/null
@@ -1,512 +1,0 @@
-#include "ssh.h"
-
-static ulong sum32(ulong, void*, int);
-
-char *msgnames[] =
-{
-/* 0 */
-	"SSH_MSG_NONE",
-	"SSH_MSG_DISCONNECT",
-	"SSH_SMSG_PUBLIC_KEY",
-	"SSH_CMSG_SESSION_KEY",
-	"SSH_CMSG_USER",
-	"SSH_CMSG_AUTH_RHOSTS",
-	"SSH_CMSG_AUTH_RSA",
-	"SSH_SMSG_AUTH_RSA_CHALLENGE",
-	"SSH_CMSG_AUTH_RSA_RESPONSE",
-	"SSH_CMSG_AUTH_PASSWORD",
-
-/* 10 */
-	"SSH_CMSG_REQUEST_PTY",
-	"SSH_CMSG_WINDOW_SIZE",
-	"SSH_CMSG_EXEC_SHELL",
-	"SSH_CMSG_EXEC_CMD",
-	"SSH_SMSG_SUCCESS",
-	"SSH_SMSG_FAILURE",
-	"SSH_CMSG_STDIN_DATA",
-	"SSH_SMSG_STDOUT_DATA",
-	"SSH_SMSG_STDERR_DATA",
-	"SSH_CMSG_EOF",
-
-/* 20 */
-	"SSH_SMSG_EXITSTATUS",
-	"SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
-	"SSH_MSG_CHANNEL_OPEN_FAILURE",
-	"SSH_MSG_CHANNEL_DATA",
-	"SSH_MSG_CHANNEL_INPUT_EOF",
-	"SSH_MSG_CHANNEL_OUTPUT_CLOSED",
-	"SSH_MSG_UNIX_DOMAIN_X11_FORWARDING (obsolete)",
-	"SSH_SMSG_X11_OPEN",
-	"SSH_CMSG_PORT_FORWARD_REQUEST",
-	"SSH_MSG_PORT_OPEN",
-
-/* 30 */
-	"SSH_CMSG_AGENT_REQUEST_FORWARDING",
-	"SSH_SMSG_AGENT_OPEN",
-	"SSH_MSG_IGNORE",
-	"SSH_CMSG_EXIT_CONFIRMATION",
-	"SSH_CMSG_X11_REQUEST_FORWARDING",
-	"SSH_CMSG_AUTH_RHOSTS_RSA",
-	"SSH_MSG_DEBUG",
-	"SSH_CMSG_REQUEST_COMPRESSION",
-	"SSH_CMSG_MAX_PACKET_SIZE",
-	"SSH_CMSG_AUTH_TIS",
-
-/* 40 */
-	"SSH_SMSG_AUTH_TIS_CHALLENGE",
-	"SSH_CMSG_AUTH_TIS_RESPONSE",
-	"SSH_CMSG_AUTH_KERBEROS",
-	"SSH_SMSG_AUTH_KERBEROS_RESPONSE",
-	"SSH_CMSG_HAVE_KERBEROS_TGT"
-};
-
-void
-badmsg(Msg *m, int want)
-{
-	char *s, buf[20+ERRMAX];
-
-	if(m==nil){
-		snprint(buf, sizeof buf, "<early eof: %r>");
-		s = buf;
-	}else{
-		snprint(buf, sizeof buf, "<unknown type %d>", m->type);
-		s = buf;
-		if(0 <= m->type && m->type < nelem(msgnames))
-			s = msgnames[m->type];
-	}
-	if(want)
-		error("got %s message expecting %s", s, msgnames[want]);
-	error("got unexpected %s message", s);
-}
-
-Msg*
-allocmsg(Conn *c, int type, int len)
-{
-	uchar *p;
-	Msg *m;
-
-	if(len > 256*1024)
-		abort();
-
-	m = (Msg*)emalloc(sizeof(Msg)+4+8+1+len+4);
-	setmalloctag(m, getcallerpc(&c));
-	p = (uchar*)&m[1];
-	m->c = c;
-	m->bp = p;
-	m->ep = p+len;
-	m->wp = p;
-	m->type = type;
-	return m;
-}
-
-void
-unrecvmsg(Conn *c, Msg *m)
-{
-	debug(DBG_PROTO, "unreceived %s len %zd\n", msgnames[m->type], m->ep - m->rp);
-	free(c->unget);
-	c->unget = m;
-}
-
-static Msg*
-recvmsg0(Conn *c)
-{
-	int pad;
-	uchar *p, buf[4];
-	ulong crc, crc0, len;
-	Msg *m;
-
-	if(c->unget){
-		m = c->unget;
-		c->unget = nil;
-		return m;
-	}
-
-	if(readn(c->fd[0], buf, 4) != 4){
-		werrstr("short net read: %r");
-		return nil;
-	}
-
-	len = LONG(buf);
-	if(len > 256*1024){
-		werrstr("packet size far too big: %.8lux", len);
-		return nil;
-	}
-
-	pad = 8 - len%8;
-
-	m = (Msg*)emalloc(sizeof(Msg)+pad+len);
-	setmalloctag(m, getcallerpc(&c));
-	m->c = c;
-	m->bp = (uchar*)&m[1];
-	m->ep = m->bp + pad+len-4;	/* -4: don't include crc */
-	m->rp = m->bp;
-
-	if(readn(c->fd[0], m->bp, pad+len) != pad+len){
-		werrstr("short net read: %r");
-		free(m);
-		return nil;
-	}
-
-	if(c->cipher)
-		c->cipher->decrypt(c->cstate, m->bp, len+pad);
-
-	crc = sum32(0, m->bp, pad+len-4);
-	p = m->bp + pad+len-4;
-	crc0 = LONG(p);
-	if(crc != crc0){
-		werrstr("bad crc %#lux != %#lux (packet length %lud)", crc, crc0, len);
-		free(m);
-		return nil;
-	}
-
-	m->rp += pad;
-	m->type = *m->rp++;
-
-	return m;
-}
-
-Msg*
-recvmsg(Conn *c, int type)
-{
-	Msg *m;
-
-	while((m = recvmsg0(c)) != nil){
-		debug(DBG_PROTO, "received %s len %zd\n", msgnames[m->type], m->ep - m->rp);
-		if(m->type != SSH_MSG_DEBUG && m->type != SSH_MSG_IGNORE)
-			break;
-		if(m->type == SSH_MSG_DEBUG)
-			debug(DBG_PROTO, "remote DEBUG: %s\n", getstring(m));
-		free(m);
-	}
-	if(type == 0){
-		/* no checking */
-	}else if(type == -1){
-		/* must not be nil */
-		if(m == nil)
-			error(Ehangup);
-	}else{
-		/* must be given type */
-		if(m==nil || m->type!=type)
-			badmsg(m, type);
-	}
-	setmalloctag(m, getcallerpc(&c));
-	return m;
-}
-
-int
-sendmsg(Msg *m)
-{
-	int i, pad;
-	uchar *p;
-	ulong datalen, len, crc;
-	Conn *c;
-
-	datalen = m->wp - m->bp;
-	len = datalen + 5;
-	pad = 8 - len%8;
-
-	debug(DBG_PROTO, "sending %s len %lud\n", msgnames[m->type], datalen);
-
-	p = m->bp;
-	memmove(m->bp+4+pad+1, m->bp, datalen);	/* slide data to correct position */
-
-	PLONG(p, len);
-	p += 4;
-
-	if(m->c->cstate){
-		for(i=0; i<pad; i++)
-			*p++ = fastrand();
-	}else{
-		memset(p, 0, pad);
-		p += pad;
-	}
-
-	*p++ = m->type;
-
-	/* data already in position */
-	p += datalen;
-
-	crc = sum32(0, m->bp+4, pad+1+datalen);
-	PLONG(p, crc);
-	p += 4;
-
-	c = m->c;
-	qlock(c);
-	if(c->cstate)
-		c->cipher->encrypt(c->cstate, m->bp+4, len+pad);
-
-	if(write(c->fd[1], m->bp, p - m->bp) != p-m->bp){
-		qunlock(c);
-		free(m);
-		return -1;
-	}
-	qunlock(c);
-	free(m);
-	return 0;
-}
-
-uchar
-getbyte(Msg *m)
-{
-	if(m->rp >= m->ep)
-		error(Edecode);
-	return *m->rp++;
-}
-
-ushort
-getshort(Msg *m)
-{
-	ushort x;
-
-	if(m->rp+2 > m->ep)
-		error(Edecode);
-
-	x = SHORT(m->rp);
-	m->rp += 2;
-	return x;
-}
-
-ulong
-getlong(Msg *m)
-{
-	ulong x;
-
-	if(m->rp+4 > m->ep)
-		error(Edecode);
-
-	x = LONG(m->rp);
-	m->rp += 4;
-	return x;
-}
-
-char*
-getstring(Msg *m)
-{
-	char *p;
-	ulong len;
-
-	/* overwrites length to make room for NUL */
-	len = getlong(m);
-	if(m->rp+len > m->ep)
-		error(Edecode);
-	p = (char*)m->rp-1;
-	memmove(p, m->rp, len);
-	p[len] = '\0';
-	return p;
-}
-
-void*
-getbytes(Msg *m, int n)
-{
-	uchar *p;
-
-	if(m->rp+n > m->ep)
-		error(Edecode);
-	p = m->rp;
-	m->rp += n;
-	return p;
-}
-
-mpint*
-getmpint(Msg *m)
-{
-	int n;
-
-	n = (getshort(m)+7)/8;	/* getshort returns # bits */
-	return betomp(getbytes(m, n), n, nil);
-}
-
-RSApub*
-getRSApub(Msg *m)
-{
-	RSApub *key;
-
-	getlong(m);
-	key = rsapuballoc();
-	if(key == nil)
-		error(Ememory);
-	key->ek = getmpint(m);
-	key->n = getmpint(m);
-	setmalloctag(key, getcallerpc(&m));
-	return key;
-}
-
-void
-putbyte(Msg *m, uchar x)
-{
-	if(m->wp >= m->ep)
-		error(Eencode);
-	*m->wp++ = x;
-}
-
-void
-putshort(Msg *m, ushort x)
-{
-	if(m->wp+2 > m->ep)
-		error(Eencode);
-	PSHORT(m->wp, x);
-	m->wp += 2;
-}
-
-void
-putlong(Msg *m, ulong x)
-{
-	if(m->wp+4 > m->ep)
-		error(Eencode);
-	PLONG(m->wp, x);
-	m->wp += 4;
-}
-
-void
-putstring(Msg *m, char *s)
-{
-	int len;
-
-	len = strlen(s);
-	putlong(m, len);
-	putbytes(m, s, len);
-}
-
-void
-putbytes(Msg *m, void *a, long n)
-{
-	if(m->wp+n > m->ep)
-		error(Eencode);
-	memmove(m->wp, a, n);
-	m->wp += n;
-}
-
-void
-putmpint(Msg *m, mpint *b)
-{
-	int bits, n;
-
-	bits = mpsignif(b);
-	putshort(m, bits);
-	n = (bits+7)/8;
-	if(m->wp+n > m->ep)
-		error(Eencode);
-	mptobe(b, m->wp, n, nil);
-	m->wp += n;
-}
-
-void
-putRSApub(Msg *m, RSApub *key)
-{
-	putlong(m, mpsignif(key->n));
-	putmpint(m, key->ek);
-	putmpint(m, key->n);
-}
-
-static ulong crctab[256];
-
-static void
-initsum32(void)
-{
-	ulong crc, poly;
-	int i, j;
-
-	poly = 0xEDB88320;
-	for(i = 0; i < 256; i++){
-		crc = i;
-		for(j = 0; j < 8; j++){
-			if(crc & 1)
-				crc = (crc >> 1) ^ poly;
-			else
-				crc >>= 1;
-		}
-		crctab[i] = crc;
-	}
-}
-
-static ulong
-sum32(ulong lcrc, void *buf, int n)
-{
-	static int first=1;
-	uchar *s = buf;
-	ulong crc = lcrc;
-
-	if(first){
-		first=0;
-		initsum32();
-	}
-	while(n-- > 0)
-		crc = crctab[(crc^*s++)&0xff] ^ (crc>>8);
-	return crc;
-}
-
-mpint*
-rsapad(mpint *b, int n)
-{
-	int i, pad, nbuf;
-	uchar buf[2560];
-	mpint *c;
-
-	if(n > sizeof buf)
-		error("buffer too small in rsapad");
-
-	nbuf = (mpsignif(b)+7)/8;
-	pad = n - nbuf;
-	assert(pad >= 3);
-	mptobe(b, buf, nbuf, nil);
-	memmove(buf+pad, buf, nbuf);
-
-	buf[0] = 0;
-	buf[1] = 2;
-	for(i=2; i<pad-1; i++)
-		buf[i]=1+fastrand()%255;
-	buf[pad-1] = 0;
-	c = betomp(buf, n, nil);
-	memset(buf, 0, sizeof buf);
-	return c;
-}
-
-mpint*
-rsaunpad(mpint *b)
-{
-	int i, n;
-	uchar buf[2560];
-
-	n = (mpsignif(b)+7)/8;
-	if(n > sizeof buf)
-		error("buffer too small in rsaunpad");
-	mptobe(b, buf, n, nil);
-
-	/* the initial zero has been eaten by the betomp -> mptobe sequence */
-	if(buf[0] != 2)
-		error("bad data in rsaunpad");
-	for(i=1; i<n; i++)
-		if(buf[i]==0)
-			break;
-	return betomp(buf+i, n-i, nil);
-}
-
-void
-mptoberjust(mpint *b, uchar *buf, int len)
-{
-	int n;
-
-	n = mptobe(b, buf, len, nil);
-	assert(n >= 0);
-	if(n < len){
-		len -= n;
-		memmove(buf+len, buf, n);
-		memset(buf, 0, len);
-	}
-}
-
-mpint*
-rsaencryptbuf(RSApub *key, uchar *buf, int nbuf)
-{
-	int n;
-	mpint *a, *b, *c;
-
-	n = (mpsignif(key->n)+7)/8;
-	a = betomp(buf, nbuf, nil);
-	b = rsapad(a, n);
-	mpfree(a);
-	c = rsaencrypt(key, b, nil);
-	mpfree(b);
-	return c;
-}
-
--- a/sys/src/cmd/ssh/pubkey.c
+++ /dev/null
@@ -1,227 +1,0 @@
-#include "ssh.h"
-#include <bio.h>
-#include <ctype.h>
-
-static int
-parsepubkey(char *s, RSApub *key, char **sp, int base)
-{
-	int n;
-	char *host, *p, *z;
-
-	z = nil;
-	n = strtoul(s, &p, 10);
-	host = nil;
-	if(n < 256 || !isspace(*p)){	/* maybe this is a host name */
-		host = s;
-		s = strpbrk(s, " \t");
-		if(s == nil)
-			return -1;
-		z = s;
-		*s++ = '\0';
-		s += strspn(s, " \t");
-
-		n = strtoul(s, &p, 10);
-		if(n < 256 || !isspace(*p)){
-			if(z)
-				*z = ' ';
-			return -1;
-		}
-	}
-
-	if((key->ek = strtomp(p, &p, base, nil)) == nil
-	|| (key->n = strtomp(p, &p, base, nil)) == nil
-	|| (*p != '\0' && !isspace(*p))
-	|| mpsignif(key->n) < 256){	/* 256 is just a sanity check */
-		mpfree(key->ek);
-		mpfree(key->n);
-		key->ek = nil;
-		key->n = nil;
-		if(z)
-			*z = ' ';
-		return -1;
-	}
-	if(host == nil){
-		if(*p != '\0'){
-			p += strspn(p, " \t");
-			if(*p != '\0'){
-				host = emalloc(strlen(p)+1);
-				strcpy(host, p);
-			}
-		}
-		free(s);
-	}
-	*sp = host;
-	return 0;
-}
-
-RSApub*
-readpublickey(Biobuf *b, char **sp)
-{
-	char *s;
-	RSApub *key;
-
-	key = rsapuballoc();
-	if(key == nil)
-		return nil;
-
-	for(;;){
-		if((s = Brdstr(b, '\n', 1)) == nil){
-			rsapubfree(key);
-			return nil;
-		}
-		if(s[0]=='#'){
-			free(s);
-			continue;
-		}
-		if(parsepubkey(s, key, sp, 10)==0
-		|| parsepubkey(s, key, sp, 16)==0)
-			return key;
-		fprint(2, "warning: skipping line '%s'; cannot parse\n", s);
-		free(s);
-	}
-}
-
-static int
-match(char *pattern, char *aliases)
-{
-	char *s, *snext;
-	char *a, *anext, *ae;
-
-	for(s=pattern; s && *s; s=snext){
-		if((snext=strchr(s, ',')) != nil)
-			*snext++ = '\0';
-		for(a=aliases; a && *a; a=anext){
-			if((anext=strchr(a, ',')) != nil){
-				ae = anext;
-				anext++;
-			}else
-				ae = a+strlen(a);
-			if(ae-a == strlen(s) && memcmp(s, a, ae-a)==0)
-				return 0;
-		}
-	}
-	return 1;
-}
-
-int
-findkey(char *keyfile, char *host, RSApub *key)
-{
-	char *h;
-	Biobuf *b;
-	RSApub *k;
-
-	if((b = Bopen(keyfile, OREAD)) == nil)
-		return NoKeyFile;
-
-	for(;;){
-		if((k = readpublickey(b, &h)) == nil){
-			Bterm(b);
-			return NoKey;
-		}
-		if(match(h, host) != 0){
-			free(h);
-			rsapubfree(k);
-			continue;
-		}
-		if(mpcmp(k->n, key->n) != 0 || mpcmp(k->ek, key->ek) != 0){
-			free(h);
-			rsapubfree(k);
-			Bterm(b);
-			return KeyWrong;
-		}
-		free(h);
-		rsapubfree(k);
-		Bterm(b);
-		return KeyOk;
-	}
-}
-
-int
-replacekey(char *keyfile, char *host, RSApub *hostkey)
-{
-	char *h, *nkey, *p;
-	Biobuf *br, *bw;
-	Dir *d, nd;
-	RSApub *k;
-
-	nkey = smprint("%s.new", keyfile);
-	if(nkey == nil)
-		return -1;
-
-	if((br = Bopen(keyfile, OREAD)) == nil){
-		free(nkey);
-		return -1;
-	}
-	if((bw = Bopen(nkey, OWRITE)) == nil){
-		Bterm(br);
-		free(nkey);
-		return -1;
-	}
-
-	while((k = readpublickey(br, &h)) != nil){
-		if(match(h, host) != 0){
-			Bprint(bw, "%s %d %.10B %.10B\n",
-				h, mpsignif(k->n), k->ek, k->n);
-		}
-		free(h);
-		rsapubfree(k);
-	}
-	Bprint(bw, "%s %d %.10B %.10B\n", host, mpsignif(hostkey->n), hostkey->ek, hostkey->n);
-	Bterm(bw);
-	Bterm(br);
-
-	d = dirstat(nkey);
-	if(d == nil){
-		fprint(2, "new key file disappeared?\n");
-		free(nkey);
-		return -1;
-	}
-
-	p = strrchr(d->name, '.');
-	if(p==nil || strcmp(p, ".new")!=0){
-		fprint(2, "new key file changed names? %s to %s\n", nkey, d->name);
-		free(d);
-		free(nkey);
-		return -1;
-	}
-
-	*p = '\0';
-	nulldir(&nd);
-	nd.name = d->name;
-	if(remove(keyfile) < 0){
-		fprint(2, "error removing %s: %r\n", keyfile);
-		free(d);
-		free(nkey);
-		return -1;
-	}
-	if(dirwstat(nkey, &nd) < 0){
-		fprint(2, "error renaming %s to %s: %r\n", nkey, d->name);
-		free(nkey);
-		free(d);
-		return -1;
-	}
-	free(d);
-	free(nkey);
-	return 0;
-}
-
-int
-appendkey(char *keyfile, char *host, RSApub *key)
-{
-	int fd;
-
-	if((fd = open(keyfile, OWRITE)) < 0){
-		fd = create(keyfile, OWRITE, 0666);
-		if(fd < 0){
-			fprint(2, "cannot open nor create %s: %r\n", keyfile);
-			return -1;
-		}
-	}
-	if(seek(fd, 0, 2) < 0
-	|| fprint(fd, "%s %d %.10B %.10B\n", host, mpsignif(key->n), key->ek, key->n) < 0){
-		close(fd);
-		return -1;
-	}
-	close(fd);
-	return 0;
-}
--- a/sys/src/cmd/ssh/scp.c
+++ /dev/null
@@ -1,799 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-
-int
-isatty(int fd)
-{
-	char buf[64];
-
-	buf[0] = '\0';
-	fd2path(fd, buf, sizeof buf);
-	if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
-		return 1;
-	return 0;
-}
-
-#define	OK	0x00
-#define	ERROR	0x01
-#define	FATAL	0x02
-
-char	*progname;
-
-int	dflag;
-int	fflag;
-int	iflag;
-int	pflag;
-int	rflag;
-int	tflag;
-int	vflag;
-
-int	remote;
-
-char	*exitflag = nil;
-
-void	scperror(int, char*, ...);
-void	mustbedir(char*);
-void	receive(char*);
-char	*fileaftercolon(char*);
-void	destislocal(char *cmd, int argc, char *argv[], char *dest);
-void	destisremote(char *cmd, int argc, char *argv[], char *host, char *dest);
-int	remotessh(char *host, char *cmd);
-void	send(char*);
-void	senddir(char*, int, Dir*);
-int 	getresponse(void);
-
-char	theuser[32];
-
-char	ssh[] = "/bin/ssh";
-
-int	remotefd0;
-int	remotefd1;
-
-int
-runcommand(char *cmd)
-{
-	Waitmsg *w;
-	int pid;
-	char *argv[4];
-
-	if (cmd == nil)
-		return -1;
-	switch(pid = fork()){
-	case -1:
-		return -1;
-	case 0:
-		argv[0] = "rc";
-		argv[1] = "-c";
-		argv[2] = cmd;
-		argv[3] = nil;
-		exec("/bin/rc", argv);
-		exits("exec failed");
-	}
-	for(;;){
-		w = wait();
-		if(w == nil)
-			return -1;
-		if(w->pid == pid)
-			break;
-		free(w);
-	}
-	if(w->msg[0]){
-		free(w);
-		return -1;
-	}
-	free(w);
-	return 1;
-}
-
-void
-vprint(char *fmt, ...)
-{
-	char buf[1024];
-	va_list arg;
-	static char *name;
-
-	if(vflag == 0)
-		return;
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-
-	if(name == nil){
-		name = sysname();
-		if(name == nil)
-			name = "<unknown>";
-	}
-	fprint(2, "%s: %s\n", name, buf);
-}
-
-void
-usage(void)
-{
-	fprint(2, "Usage: scp [-Iidfprtv] source ... destination\n");
-	exits("usage");
-}
-
-
-#pragma	varargck	type	"F"	int
-#pragma	varargck	type	"V"	char*
-static int flag;
-
-/* flag: if integer flag, take following char *value */
-int
-flagfmt(Fmt *f)
-{
-	flag = va_arg(f->args, int);
-	return 0;
-}
-
-/* flag: if previous integer flag, take char *value */
-int
-valfmt(Fmt *f)
-{
-	char *value;
-
-	value = va_arg(f->args, char*);
-	if(flag)
-		return fmtprint(f, " %s", value);
-	return 0;
-}
-
-void
-sendokresponse(void)
-{
-	char ok = OK;
-
-	write(remotefd1, &ok, 1);
-}
-
-void
-main(int argc, char *argv[])
-{
-	int i, fd;
-	char cmd[32];
-	char *p;
-
-	progname = argv[0];
-	fmtinstall('F', flagfmt);
-	fmtinstall('V', valfmt);
-	iflag = -1;
-
-	ARGBEGIN {
-	case 'I':
-		iflag = 0;
-		break;
-	case 'i':
-		iflag = 1;
-		break;
-	case 'd':
-		dflag++;
-		break;
-	case 'f':
-		fflag++;
-		remote++;
-		break;
-	case 'p':
-		pflag++;
-		break;
-	case 'r':
-		rflag++;
-		break;
-	case 't':
-		tflag++;
-		remote++;
-		break;
-	case 'v':
-		vflag++;
-		break;
-	default:
-		scperror(1, "unknown option %c", ARGC());
-	} ARGEND
-
-	if(iflag == -1)
-		iflag = isatty(0);
-
-	remotefd0 = 0;
-	remotefd1 = 1;
-
-	if(fflag){
-		getresponse();
-		for(i=0; i<argc; i++)
-			send(argv[i]);
-		exits(0);
-	}
-	if(tflag){
-		if(argc != 1)
-			usage();
-		receive(argv[0]);
-		exits(0);
-	}
-
-	if (argc < 2)
-		usage();
-	if (argc > 2)
-		dflag = 1;
-
-	i = 0;
-	fd = open("/dev/user", OREAD);
-	if(fd >= 0){
-		i = read(fd, theuser, sizeof theuser - 1);
-		close(fd);
-	}
-	if(i <= 0)
-		scperror(1, "can't read /dev/user: %r");
-
-	remotefd0 = -1;
-	remotefd1 = -1;
-
-	snprint(cmd, sizeof cmd, "scp%F%V%F%V%F%V%F%V",
-		dflag, "-d",
-		pflag, "-p",
-		rflag, "-r",
-		vflag, "-v");
-
-	p = fileaftercolon(argv[argc-1]);
-	if(p != nil)	/* send to remote machine. */
-		destisremote(cmd, argc-1, argv, argv[argc-1], p);
-	else{
-		if(dflag)
-			mustbedir(argv[argc-1]);
-		destislocal(cmd, argc-1, argv, argv[argc-1]);
-	}
-
-	exits(exitflag);
-}
-
-void
-destislocal(char *cmd, int argc, char *argv[], char *dst)
-{
-	int i;
-	char *src;
-	char buf[4096];
-
-	for(i = 0; i<argc; i++){
-		src = fileaftercolon(argv[i]);
-		if(src == nil){
-			/* local file; no network */
-			snprint(buf, sizeof buf, "exec cp%F%V%F%V %s %s",
-				rflag, "-r",
-				pflag, "-p",
-				argv[i], dst);
-	  		vprint("remotetolocal: %s", buf);
-			if(runcommand(buf) < 0)
-				exitflag = "local cp exec";
-		}else{
-			/* remote file; use network */
-			snprint(buf, sizeof buf, "%s -f %s", cmd, src);
-		  	if(remotessh(argv[i], buf) < 0)
-				exitflag = "remote ssh exec";
-			else{
-				receive(dst);
-				close(remotefd0);
-				remotefd0 = -1;
-				remotefd1 = -1;
-			}
-		}
-	}
-}
-
-void
-destisremote(char *cmd, int argc, char *argv[], char *host, char *dest)
-{
-	int i;
-	char *src;
-	char buf[4096];
-
-	for(i = 0; i < argc; i++){
-		vprint("remote destination: send %s to %s:%s", argv[i], host, dest);
-		/* destination is remote, but source may be local */
-		src = fileaftercolon(argv[i]);
-		if(src != nil){
-			/* remote to remote */
-			snprint(buf, sizeof buf, "exec %s%F%V%F%V %s %s %s '%s:%s'",
-				ssh,
-				iflag, " -i",
-				vflag, "-v",
-				argv[i], cmd, src,
-				host, dest);
-			vprint("localtoremote: %s", buf);
-			runcommand(buf);
-		}else{
-			/* local to remote */
-			if(remotefd0 == -1){
-				snprint(buf, sizeof buf, "%s -t %s", cmd, dest);
-				if(remotessh(host, buf) < 0)
-					exits("remotessh");
-				if(getresponse() < 0)
-					exits("bad response");
-			}
-			send(argv[i]);
-		}
-	}
-}
-
-void
-readhdr(char *p, int n)
-{
-	int i;
-
-	for(i=0; i<n; i++){
-		if(read(remotefd0, &p[i], 1) != 1)
-			break;
-		if(p[i] == '\n'){
-			p[i] = '\0';
-			return;
-		}
-	}
-	/* if at beginning, this is regular EOF */
-	if(i == 0)
-		exits(nil);
-	scperror(1, "read error on receive header: %r");
-}
-
-Dir *
-receivedir(char *dir, int exists, Dir *d, int settimes, ulong atime, ulong mtime, ulong mode)
-{
-	Dir nd;
-	int setmodes;
-	int fd;
-
-	setmodes = pflag;
-	if(exists){
-		if(!(d->qid.type & QTDIR)) {
-			scperror(0, "%s: protocol botch: directory requrest for non-directory", dir);
-			return d;
-		}
-	}else{
-		/* create it writeable; will fix later */
-		setmodes = 1;
-		fd = create(dir, OREAD, DMDIR|mode|0700);
-		if (fd < 0){
-			scperror(0, "%s: can't create: %r", dir);
-			return d;
-		}
-		d = dirfstat(fd);
-		close(fd);
-		if(d == nil){
-			scperror(0, "%s: can't stat: %r", dir);
-			return d;
-		}
-	}
-	receive(dir);
-	if(settimes || setmodes){
-		nulldir(&nd);
-		if(settimes){
-			nd.atime = atime;
-			nd.mtime = mtime;
-			d->atime = nd.atime;
-			d->mtime = nd.mtime;
-		}
-		if(setmodes){
-			nd.mode = DMDIR | (mode & 0777);
-			d->mode = nd.mode;
-		}
-		if(dirwstat(dir, &nd) < 0){
-			scperror(0, "can't wstat %s: %r", dir);
-			free(d);
-			return nil;
-		}
-	}
-	return d;
-}
-
-void
-receive(char *dest)
-{
-	int isdir, settimes, mode;
-	int exists, n, i, fd, m;
-	int errors;
-	ulong atime, mtime, size;
-	char buf[8192], *p;
-	char name[1024];
-	Dir *d;
-	Dir nd;
-
-	mtime = 0L;
-	atime = 0L;
-	settimes = 0;
-	isdir = 0;
-	if ((d = dirstat(dest)) && (d->qid.type & QTDIR)) {
-		isdir = 1;
-	}
-	if(dflag && !isdir)
-		scperror(1, "%s: not a directory: %r", dest);
-
-	sendokresponse();
-
-	for (;;) {
-		readhdr(buf, sizeof buf);
-
-		switch(buf[0]){
-		case ERROR:
-		case FATAL:
-			if(!remote)
-				fprint(2, "%s\n", buf+1);
-			exitflag = "bad receive";
-			if(buf[0] == FATAL)
-				exits(exitflag);
-			continue;
-
-		case 'E':
-			sendokresponse();
-			return;
-
-		case 'T':
-			settimes = 1;
-			p = buf + 1;
-			mtime = strtol(p, &p, 10);
-			if(*p++ != ' '){
-		Badtime:
-				scperror(1, "bad time format: %s", buf+1);
-			}
-			strtol(p, &p, 10);
-			if(*p++ != ' ')
-				goto Badtime;
-			atime = strtol(p, &p, 10);
-			if(*p++ != ' ')
-				goto Badtime;
-			strtol(p, &p, 10);
-			if(*p++ != 0)
-				goto Badtime;
-
-			sendokresponse();
-			continue;
-
-		case 'D':
-		case 'C':
-			p = buf + 1;
-			mode = strtol(p, &p, 8);
-			if (*p++ != ' '){
-		Badmode:
-				scperror(1, "bad mode/size format: %s", buf+1);
-			}
-			size = strtoll(p, &p, 10);
-			if(*p++ != ' ')
-				goto Badmode;
-
-			if(isdir){
-				if(dest[0] == '\0')
-					snprint(name, sizeof name, "%s", p);
-				else
-					snprint(name, sizeof name, "%s/%s", dest, p);
-			}else
-				snprint(name, sizeof name, "%s", dest);
-			if(strlen(name) > sizeof name-UTFmax)
-				scperror(1, "file name too long: %s", dest);
-
-			exists = 1;
-			free(d);
-			if((d = dirstat(name)) == nil)
-				exists = 0;
-
-			if(buf[0] == 'D'){
-				vprint("receive directory %s", name);
-				d = receivedir(name, exists, d, settimes, atime, mtime, mode);
-				settimes = 0;
-				continue;
-			}
-
-			vprint("receive file %s by %s", name, getuser());
-			fd = create(name, OWRITE, mode);
-			if(fd < 0){
-				scperror(0, "can't create %s: %r", name);
-				continue;
-			}
-			sendokresponse();
-
-			/*
-			 * Committed to receive size bytes
-			 */
-			errors = 0;
-			for(i = 0; i < size; i += m){
-				n = sizeof buf;
-				if(n > size - i)
-					n = size - i;
-				m = readn(remotefd0, buf, n);
-				if(m <= 0)
-					scperror(1, "read error on connection: %r");
-				if(errors == 0){
-					n = write(fd, buf, m);
-					if(n != m)
-						errors = 1;
-				}
-			}
-
-			/* if file exists, modes could be wrong */
-			if(errors)
-				scperror(0, "%s: write error: %r", name);
-			else if(settimes || (exists && (d->mode&0777) != (mode&0777))){
-				nulldir(&nd);
-				if(settimes){
-					settimes = 0;
-					nd.atime = atime;
-					nd.mtime = mtime;
-				}
-				if(exists && (d->mode&0777) != (mode&0777))
-					nd.mode = (d->mode & ~0777) | (mode&0777);
-				if(dirwstat(name, &nd) < 0)
-					scperror(0, "can't wstat %s: %r", name);
-			}
-			free(d);
-			d = nil;
-			close(fd);
-			getresponse();
-			if(errors)
-				exits("write error");
-			sendokresponse();
-			break;
-
-		default:
-			scperror(0, "unrecognized header type char %c", buf[0]);	
-			scperror(1, "input line: %s", buf);	
-		}
-	}
-}
-
-/*
- * Lastelem is called when we have a Dir with the final element, but if the file
- * has been bound, we want the original name that was used rather than
- * the contents of the stat buffer, so do this lexically.
- */
-char*
-lastelem(char *file)
-{
-	char *elem;
-
-	elem = strrchr(file, '/');
-	if(elem == nil)
-		return file;
-	return elem+1;
-}
-
-void
-send(char *file)
-{
-	Dir *d;
-	ulong i;
-	int m, n, fd;
-	char buf[8192];
-
-	if((fd = open(file, OREAD)) < 0){
-		scperror(0, "can't open %s: %r", file);
-		return;
-	}
-	if((d = dirfstat(fd)) == nil){
-		scperror(0, "can't fstat %s: %r", file);
-		goto Return;
-	}
-
-	if(d->qid.type & QTDIR){
-		if(rflag)
-			senddir(file, fd, d);
-		else
-			scperror(0, "%s: is a directory", file);
-		goto Return;
-	}
-
-	if(pflag){
-		fprint(remotefd1, "T%lud 0 %lud 0\n", d->mtime, d->atime);
-		if(getresponse() < 0)
-			goto Return;
-	}
-
-	fprint(remotefd1, "C%.4luo %lld %s\n", d->mode&0777, d->length, lastelem(file));
-	if(getresponse() < 0)
-		goto Return;
-
-	/*
-	 * We are now committed to send d.length bytes, regardless
-	 */
-	for(i=0; i<d->length; i+=m){
-		n = sizeof buf;
-		if(n > d->length - i)
-			n = d->length - i;
-		m = readn(fd, buf, n);
-		if(m <= 0)
-			break;
-		write(remotefd1, buf, m);
-	}
-
-	if(i == d->length)
-		sendokresponse();
-	else{
-		/* continue to send gibberish up to d.length */
-		for(; i<d->length; i+=n){
-			n = sizeof buf;
-			if(n > d->length - i)
-				n = d->length - i;
-			write(remotefd1, buf, n);
-		}
-		scperror(0, "%s: %r", file);
-	}
-		
-	getresponse();
-
-    Return:
-	free(d);
-	close(fd);
-}
-
-int
-getresponse(void)
-{
-	uchar first, byte, buf[256];
-	int i;
-
-	if (read(remotefd0, &first, 1) != 1)
-		scperror(1, "lost connection");
-
-	if(first == 0)
-		return 0;
-
-	i = 0;
-	if(first > FATAL){
-		fprint(2, "scp: unexpected response character 0x%.2ux\n", first);
-		buf[i++] = first;
-	}
-
-	/* read error message up to newline */
-	for(;;){
-		if(read(remotefd0, &byte, 1) != 1)
-			scperror(1, "response: dropped connection");
-		if(byte == '\n')
-			break;
-		if(i < sizeof buf)
-			buf[i++] = byte;
-	}
-
-	exitflag = "bad response";
-	if(!remote)
-		fprint(2, "%.*s\n", utfnlen((char*)buf, i), (char*)buf);
-
-	if (first == ERROR)
-		return -1;
-	exits(exitflag);
-	return 0;	/* not reached */
-}
-
-void
-senddir(char *name, int fd, Dir *dirp)
-{
-	Dir *d, *dir;
-	int n;
-	char file[256];
-
-	if(pflag){
-		fprint(remotefd1, "T%lud 0 %lud 0\n", dirp->mtime, dirp->atime);
-		if(getresponse() < 0)
-			return;
-	}
-
-	vprint("directory %s mode: D%.4lo %d %.1024s", name, dirp->mode&0777, 0, lastelem(name));
-
-	fprint(remotefd1, "D%.4lo %d %.1024s\n", dirp->mode&0777, 0, dirp->name);
-	if(getresponse() < 0)
-		return;
-
-	n = dirreadall(fd, &dir);
-	for(d = dir; d < &dir[n]; d++){
-		/* shouldn't happen with plan 9, but worth checking anyway */
-		if(strcmp(d->name, ".")==0 || strcmp(d->name, "..")==0)
-			continue;
-		if(snprint(file, sizeof file, "%s/%s", name, d->name) > sizeof file-UTFmax){
-			scperror(0, "%.20s.../%s: name too long; skipping file", file, d->name);
-			continue;
-		}
-		send(file);
-	}
-	free(dir);
-	fprint(remotefd1, "E\n");
-	getresponse();
-}
-
-int
-remotessh(char *host, char *cmd)
-{
-	int i, p[2];
-	char *arg[32];
-
-	vprint("remotessh: %s: %s", host, cmd);
-
-	if(pipe(p) < 0)
-		scperror(1, "pipe: %r");
-
-	switch(fork()){
-	case -1:
-		scperror(1, "fork: %r");
-
-	case 0:
-		/* child */
-		close(p[0]);
-		dup(p[1], 0);
-		dup(p[1], 1);
-		for (i = 3; i < 100; i++)
-			close(i);
-	
-		i = 0;
-		arg[i++] = ssh;
-		arg[i++] = "-x";
-		arg[i++] = "-a";
-		arg[i++] = "-m";
-		if(iflag)
-			arg[i++] = "-i";
-		if(vflag)
-			arg[i++] = "-v";
-		arg[i++] = host;
-		arg[i++] = cmd;
-		arg[i] = nil;
-	
-		exec(ssh, arg);
-		exits("exec failed");
-
-	default:
-		/* parent */
-		close(p[1]);
-		remotefd0 = p[0];
-		remotefd1 = p[0];
-	}
-	return 0;
-}
-
-void
-scperror(int exit, char *fmt, ...)
-{
-	char buf[2048];
-	va_list arg;
-
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-
-	fprint(remotefd1, "%cscp: %s\n", ERROR, buf);
-
-	if (!remote)
-		fprint(2, "scp: %s\n", buf);
-	exitflag = buf;
-	if(exit)
-		exits(exitflag);
-}
-
-char *
-fileaftercolon(char *file)
-{
-	char *c, *s;
-
-	c = utfrune(file, ':');
-	if(c == nil)
-		return nil;
-
-	/* colon must be in middle of name to be a separator */
-	if(c == file)
-		return nil;
-
-	/* does slash occur before colon? */
-	s = utfrune(file, '/');
-	if(s != nil && s < c)
-		return nil;
-
-	*c++ = '\0';
-	if(*c == '\0')
-		return ".";
-	return c;
-}
-
-void
-mustbedir(char *file)
-{
-	Dir *d;
-
-	if((d = dirstat(file)) == nil){
-		scperror(1, "%s: %r", file);
-		return;
-	}
-	if(!(d->qid.type & QTDIR))
-		scperror(1, "%s: Not a directory", file);
-	free(d);
-}
--- a/sys/src/cmd/ssh/smsg.c
+++ /dev/null
@@ -1,285 +1,0 @@
-#include "ssh.h"
-#include <bio.h>
-
-static void
-send_ssh_smsg_public_key(Conn *c)
-{
-	int i;
-	Msg *m;
-
-	m = allocmsg(c, SSH_SMSG_PUBLIC_KEY, 2048);
-	putbytes(m, c->cookie, COOKIELEN);
-	putRSApub(m, c->serverkey);
-	putRSApub(m, c->hostkey);
-	putlong(m, c->flags);
-
-	for(i=0; i<c->nokcipher; i++)
-		c->ciphermask |= 1<<c->okcipher[i]->id;
-	putlong(m, c->ciphermask);
-	for(i=0; i<c->nokauthsrv; i++)
-		c->authmask |= 1<<c->okauthsrv[i]->id;
-	putlong(m, c->authmask);
-
-	sendmsg(m);
-}
-
-static mpint*
-rpcdecrypt(AuthRpc *rpc, mpint *b)
-{
-	mpint *a;
-	char *p;
-
-	p = mptoa(b, 16, nil, 0);
-	if(auth_rpc(rpc, "write", p, strlen(p)) != ARok)
-		sysfatal("factotum rsa write: %r");
-	free(p);
-	if(auth_rpc(rpc, "read", nil, 0) != ARok)
-		sysfatal("factotum rsa read: %r");
-	a = strtomp(rpc->arg, nil, 16, nil);
-	mpfree(b);
-	return a;
-}
-
-static void
-recv_ssh_cmsg_session_key(Conn *c, AuthRpc *rpc)
-{
-	int i, id, n, serverkeylen, hostkeylen;
-	mpint *a, *b;
-	uchar *buf;
-	Msg *m;
-	RSApriv *ksmall, *kbig;
-
-	m = recvmsg(c, SSH_CMSG_SESSION_KEY);
-	id = getbyte(m);
-	c->cipher = nil;
-	for(i=0; i<c->nokcipher; i++)
-		if(c->okcipher[i]->id == id)
-			c->cipher = c->okcipher[i];
-	if(c->cipher == nil)
-		sysfatal("invalid cipher selected");
-
-	if(memcmp(getbytes(m, COOKIELEN), c->cookie, COOKIELEN) != 0)
-		sysfatal("bad cookie");
-
-	serverkeylen = mpsignif(c->serverkey->n);
-	hostkeylen = mpsignif(c->hostkey->n);
-	ksmall = kbig = nil;
-	if(serverkeylen+128 <= hostkeylen){
-		ksmall = c->serverpriv;
-		kbig = nil;
-	}else if(hostkeylen+128 <= serverkeylen){
-		ksmall = nil;
-		kbig = c->serverpriv;
-	}else
-		sysfatal("server session and host keys do not differ by at least 128 bits");
-
-	b = getmpint(m);
-
-	debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b);
-	if(kbig){
-		a = rsadecrypt(kbig, b, nil);
-		mpfree(b);
-		b = a;
-	}else
-		b = rpcdecrypt(rpc, b);
-	a = rsaunpad(b);
-	mpfree(b);
-	b = a;
-
-	debug(DBG_CRYPTO, "encrypted with ksmall is %B\n", b);
-	if(ksmall){
-		a = rsadecrypt(ksmall, b, nil);
-		mpfree(b);
-		b = a;
-	}else
-		b = rpcdecrypt(rpc, b);
-	a = rsaunpad(b);
-	mpfree(b);
-	b = a;
-
-	debug(DBG_CRYPTO, "munged is %B\n", b);
-
-	n = (mpsignif(b)+7)/8;
-	if(n > SESSKEYLEN)
-		sysfatal("client sent short session key");
-
-	buf = emalloc(SESSKEYLEN);
-	mptoberjust(b, buf, SESSKEYLEN);
-	mpfree(b);
-
-	for(i=0; i<SESSIDLEN; i++)
-		buf[i] ^= c->sessid[i];
-
-	memmove(c->sesskey, buf, SESSKEYLEN);
-
-	debug(DBG_CRYPTO, "unmunged is %.*H\n", SESSKEYLEN, buf);
-
-	c->flags = getlong(m);
-	free(m);
-}
-
-static AuthInfo*
-responselogin(char *user, char *resp)
-{
-	Chalstate *c;
-	AuthInfo *ai;
-
-	if((c = auth_challenge("proto=p9cr user=%q role=server", user)) == nil){
-		sshlog("auth_challenge failed for %s", user);
-		return nil;
-	}
-	c->resp = resp;
-	c->nresp = strlen(resp);
-	ai = auth_response(c);
-	auth_freechal(c);
-	return ai;
-}
-
-static AuthInfo*
-authusername(Conn *c)
-{
-	char *p;
-	AuthInfo *ai;
-
-	/*
-	 * hack for sam users: 'name numbers' gets tried as securid login.
-	 */
-	if(p = strchr(c->user, ' ')){
-		*p++ = '\0';
-		if((ai=responselogin(c->user, p)) != nil)
-			return ai;
-		*--p = ' ';
-		sshlog("bad response: %s", c->user);
-	}
-	return nil;
-}
-
-static void
-authsrvuser(Conn *c)
-{
-	int i;
-	char *ns, *user;
-	AuthInfo *ai;
-	Msg *m;
-
-	m = recvmsg(c, SSH_CMSG_USER);
-	user = getstring(m);
-	c->user = emalloc(strlen(user)+1);
-	strcpy(c->user, user);
-	free(m);
-
-	ai = authusername(c);
-	while(ai == nil){
-		/*
-		 * clumsy: if the client aborted the auth_tis early
-		 * we don't send a new failure.  we check this by
-		 * looking at c->unget, which is only used in that
-		 * case.
-		 */
-		if(c->unget != nil)
-			goto skipfailure;
-		sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
-	skipfailure:
-		m = recvmsg(c, -1);
-		for(i=0; i<c->nokauthsrv; i++)
-			if(c->okauthsrv[i]->firstmsg == m->type){
-				ai = (*c->okauthsrv[i]->fn)(c, m);
-				break;
-			}
-		if(i==c->nokauthsrv)
-			badmsg(m, 0);
-	}
-	sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
-
-	if(noworld(ai->cuid))
-		ns = "/lib/namespace.noworld";
-	else
-		ns = nil;
-	if(auth_chuid(ai, ns) < 0){
-		sshlog("auth_chuid to %s: %r", ai->cuid);
-		sysfatal("auth_chuid: %r");
-	}
-	sshlog("logged in as %s", ai->cuid);
-	auth_freeAI(ai);
-}
-
-void
-sshserverhandshake(Conn *c)
-{
-	char *p, buf[128];
-	Biobuf *b;
-	Attr *a;
-	int i, afd;
-	mpint *m;
-	AuthRpc *rpc;
-	RSApub *key;
-
-	/*
-	 * BUG: should use `attr' to get the key attributes
-	 * after the read, but that's not implemented yet.
-	 */
-	if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
-		sysfatal("open /mnt/factotum/ctl: %r");
-	while((p = Brdline(b, '\n')) != nil){
-		p[Blinelen(b)-1] = '\0';
-		if(strstr(p, " proto=rsa ") && strstr(p, " service=sshserve "))
-			break;
-	}
-	if(p == nil)
-		sysfatal("no sshserve keys found in /mnt/factotum/ctl");
-	a = _parseattr(p);
-	Bterm(b);
-	key = emalloc(sizeof(*key));
-	if((p = _strfindattr(a, "n")) == nil)
-		sysfatal("no n in sshserve key");
-	if((key->n = strtomp(p, &p, 16, nil)) == nil || *p != 0)
-		sysfatal("bad n in sshserve key");
-	if((p = _strfindattr(a, "ek")) == nil)
-		sysfatal("no ek in sshserve key");
-	if((key->ek = strtomp(p, &p, 16, nil)) == nil || *p != 0)
-		sysfatal("bad ek in sshserve key");
-	_freeattr(a);
-
-	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
-		sysfatal("open /mnt/factotum/rpc: %r");
-	if((rpc = auth_allocrpc(afd)) == nil)
-		sysfatal("auth_allocrpc: %r");
-	p = "proto=rsa role=client service=sshserve";
-	if(auth_rpc(rpc, "start", p, strlen(p)) != ARok)
-		sysfatal("auth_rpc start %s: %r", p);
-	if(auth_rpc(rpc, "read", nil, 0) != ARok)
-		sysfatal("auth_rpc read: %r");
-	m = strtomp(rpc->arg, nil, 16, nil);
-	if(mpcmp(m, key->n) != 0)
-		sysfatal("key in /mnt/factotum/ctl does not match rpc key");
-	mpfree(m);
-	c->hostkey = key;
-
-	/* send id string */
-	fprint(c->fd[0], "SSH-1.5-Plan9\n");
-
-	/* receive id string */
-	if(readstrnl(c->fd[0], buf, sizeof buf) < 0)
-		sysfatal("reading server version: %r");
-
-	/* id string is "SSH-m.n-comment".  We need m=1, n>=5. */
-	if(strncmp(buf, "SSH-", 4) != 0
-	|| strtol(buf+4, &p, 10) != 1
-	|| *p != '.'
-	|| strtol(p+1, &p, 10) < 5
-	|| *p != '-')
-		sysfatal("protocol mismatch; got %s, need SSH-1.x for x>=5", buf);
-
-	for(i=0; i<COOKIELEN; i++)
-		c->cookie[i] = fastrand();
-	calcsessid(c);
-	send_ssh_smsg_public_key(c);
-	recv_ssh_cmsg_session_key(c, rpc);
-	auth_freerpc(rpc);
-	close(afd);
-
-	c->cstate = (*c->cipher->init)(c, 1);		/* turns on encryption */
-	sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
-
-	authsrvuser(c);
-}
--- a/sys/src/cmd/ssh/ssh.c
+++ /dev/null
@@ -1,592 +1,0 @@
-#include "ssh.h"
-
-int cooked = 0;		/* user wants cooked mode */
-int raw = 0;		/* console is in raw mode */
-int crstrip;
-int interactive = -1;
-int usemenu = 1;
-int isatty(int);
-int rawhack;
-int forwardagent = 0;
-char *buildcmd(int, char**);
-void fromnet(Conn*);
-void fromstdin(Conn*);
-void winchanges(Conn*);
-static void	sendwritemsg(Conn *c, char *buf, int n);
-
-Cipher *allcipher[] = {
-	&cipherrc4,
-	&cipherblowfish,
-	&cipher3des,
-	&cipherdes,
-	&ciphernone,
-	&ciphertwiddle,
-};
-
-Auth *allauth[] = {
-	&authpassword,
-	&authrsa,
-	&authtis,
-};
-
-char *cipherlist = "blowfish rc4 3des";
-char *authlist = "rsa password tis";
-
-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;
-}
-
-Auth*
-findauth(char *name, Auth **list, int nlist)
-{
-	int i;
-
-	for(i=0; i<nlist; i++)
-		if(strcmp(name, list[i]->name) == 0)
-			return list[i];
-	error("unknown auth %s", name);
-	return nil;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: ssh [-CiImPpRr] [-A authlist] [-c cipherlist] [user@]hostname [cmd [args]]\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int i, dowinchange, fd, usepty;
-	char *host, *cmd, *user, *p;
-	char *f[16];
-	Conn c;
-	Msg *m;
-
-	fmtinstall('B', mpfmt);
-	fmtinstall('H', encodefmt);
-	atexit(atexitkiller);
-	atexitkill(getpid());
-
-	dowinchange = 0;
-	if(getenv("LINES"))
-		dowinchange = 1;
-	usepty = -1;
-	user = nil;
-	ARGBEGIN{
-	case 'B':	/* undocumented, debugging */
-		doabort = 1;
-		break;
-	case 'D':	/* undocumented, debugging */
-		debuglevel = strtol(EARGF(usage()), nil, 0);
-		break;
-	case 'l':	/* deprecated */
-	case 'u':
-		user = EARGF(usage());
-		break;
-	case 'a':	/* used by Unix scp implementations; we must ignore them. */
-	case 'x':
-		break;
-
-	case 'A':
-		authlist = EARGF(usage());
-		break;
-	case 'C':
-		cooked = 1;
-		break;
-	case 'c':
-		cipherlist = EARGF(usage());
-		break;
-	case 'f':
-		forwardagent = 1;
-		break;
-	case 'I':
-		interactive = 0;
-		break;
-	case 'i':
-		interactive = 1;
-		break;
-	case 'm':
-		usemenu = 0;
-		break;
-	case 'P':
-		usepty = 0;
-		break;
-	case 'p':
-		usepty = 1;
-		break;
-	case 'R':
-		rawhack = 1;
-		break;
-	case 'r':
-		crstrip = 1;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc < 1)
-		usage();
-
-	host = argv[0];
-
-	cmd = nil;
-	if(argc > 1)
-		cmd = buildcmd(argc-1, argv+1);
-
-	if((p = strchr(host, '@')) != nil){
-		*p++ = '\0';
-		user = host;
-		host = p;
-	}
-	if(user == nil)
-		user = getenv("user");
-	if(user == nil)
-		sysfatal("cannot find user name");
-
-	privatefactotum();
-	if(interactive==-1)
-		interactive = isatty(0);
-
-	if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
-		sysfatal("dialing %s: %r", host);
-
-	memset(&c, 0, sizeof c);
-	c.interactive = interactive;
-	c.fd[0] = c.fd[1] = fd;
-	c.user = user;
-	c.host = host;
-	setaliases(&c, host);
-
-	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.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
-	c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
-	for(i=0; i<c.nokauth; i++)
-		c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
-
-	sshclienthandshake(&c);
-
-	if(forwardagent){
-		if(startagent(&c) < 0)
-			forwardagent = 0;
-	}
-	if(usepty == -1)
-		usepty = cmd==nil;
-	if(usepty)
-		requestpty(&c);
-	if(cmd){
-		m = allocmsg(&c, SSH_CMSG_EXEC_CMD, 4+strlen(cmd));
-		putstring(m, cmd);
-	}else
-		m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
-	sendmsg(m);
-
-	fromstdin(&c);
-	rfork(RFNOTEG);	/* only fromstdin gets notes */
-	if(dowinchange)
-		winchanges(&c);
-	fromnet(&c);
-	exits(0);
-}
-
-int
-isatty(int fd)
-{
-	char buf[64];
-
-	buf[0] = '\0';
-	fd2path(fd, buf, sizeof buf);
-	if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
-		return 1;
-	return 0;
-}
-
-char*
-buildcmd(int argc, char **argv)
-{
-	int i, len;
-	char *s, *t;
-
-	len = argc-1;
-	for(i=0; i<argc; i++)
-		len += strlen(argv[i]);
-	s = emalloc(len+1);
-	t = s;
-	for(i=0; i<argc; i++){
-		if(i)
-			*t++ = ' ';
-		strcpy(t, argv[i]);
-		t += strlen(t);
-	}
-	return s;
-}
-
-void
-fromnet(Conn *c)
-{
-	int fd, len;
-	char *s, *es, *r, *w;
-	ulong ex;
-	char buf[64];
-	Msg *m;
-
-	for(;;){
-		m = recvmsg(c, -1);
-		if(m == nil)
-			break;
-		switch(m->type){
-		default:
-			badmsg(m, 0);
-
-		case SSH_SMSG_EXITSTATUS:
-			ex = getlong(m);
-			if(ex==0)
-				exits(0);
-			sprint(buf, "%lud", ex);
-			exits(buf);
-
-		case SSH_MSG_DISCONNECT:
-			s = getstring(m);
-			error("disconnect: %s", s);
-
-		/*
-		 * If we ever add reverse port forwarding, we'll have to
-		 * revisit this.  It assumes that the agent connections are
-		 * the only ones.
-		 */
-		case SSH_SMSG_AGENT_OPEN:
-			if(!forwardagent)
-				error("server tried to use agent forwarding");
-			handleagentopen(m);
-			break;
-		case SSH_MSG_CHANNEL_INPUT_EOF:
-			if(!forwardagent)
-				error("server tried to use agent forwarding");
-			handleagentieof(m);
-			break;
-		case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
-			if(!forwardagent)
-				error("server tried to use agent forwarding");
-			handleagentoclose(m);
-			break;
-		case SSH_MSG_CHANNEL_DATA:
-			if(!forwardagent)
-				error("server tried to use agent forwarding");
-			handleagentmsg(m);
-			break;
-
-		case SSH_SMSG_STDOUT_DATA:
-			fd = 1;
-			goto Dataout;
-		case SSH_SMSG_STDERR_DATA:
-			fd = 2;
-			goto Dataout;
-		Dataout:
-			len = getlong(m);
-			s = (char*)getbytes(m, len);
-			if(crstrip){
-				es = s+len;
-				for(r=w=s; r<es; r++)
-					if(*r != '\r')
-						*w++ = *r;
-				len = w-s;
-			}
-			write(fd, s, len);
-			break;
-		}
-		free(m);
-	}
-}		
-
-/*
- * Lifted from telnet.c, con.c
- */
-
-static int consctl = -1;
-static int outfd1=1, outfd2=2;	/* changed during system */
-static void system(Conn*, char*);
-
-/*
- *  turn keyboard raw mode on
- */
-static void
-rawon(void)
-{
-	if(raw)
-		return;
-	if(cooked)
-		return;
-	if(consctl < 0)
-		consctl = open("/dev/consctl", OWRITE);
-	if(consctl < 0)
-		return;
-	if(write(consctl, "rawon", 5) != 5)
-		return;
-	raw = 1;
-}
-
-/*
- *  turn keyboard raw mode off
- */
-static void
-rawoff(void)
-{
-	if(raw == 0)
-		return;
-	if(consctl < 0)
-		return;
-	if(write(consctl, "rawoff", 6) != 6)
-		return;
-	close(consctl);
-	consctl = -1;
-	raw = 0;
-}
-
-/*
- *  control menu
- */
-#define STDHELP	"\t(q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
-
-static int
-menu(Conn *c)
-{
-	char buf[1024];
-	long n;
-	int done;
-	int wasraw;
-
-	wasraw = raw;
-	if(wasraw)
-		rawoff();
-
-	buf[0] = '?';
-	fprint(2, ">>> ");
-	for(done = 0; !done; ){
-		n = read(0, buf, sizeof(buf)-1);
-		if(n <= 0)
-			return -1;
-		buf[n] = 0;
-		switch(buf[0]){
-		case '!':
-			print(buf);
-			system(c, buf+1);
-			print("!\n");
-			done = 1;
-			break;
-		case 'i':
-			buf[0] = 0x1c;
-			sendwritemsg(c, buf, 1);
-			done = 1;
-			break;
-		case '.':
-		case 'q':
-			done = 1;
-			break;
-		case 'r':
-			crstrip = 1-crstrip;
-			done = 1;
-			break;
-		default:
-			fprint(2, STDHELP);
-			break;
-		}
-		if(!done)
-			fprint(2, ">>> ");
-	}
-
-	if(wasraw)
-		rawon();
-	else
-		rawoff();
-	return buf[0];
-}
-
-static void
-sendwritemsg(Conn *c, char *buf, int n)
-{
-	Msg *m;
-
-	if(n==0)
-		m = allocmsg(c, SSH_CMSG_EOF, 0);
-	else{
-		m = allocmsg(c, SSH_CMSG_STDIN_DATA, 4+n);
-		putlong(m, n);
-		putbytes(m, buf, n);
-	}
-	sendmsg(m);
-}
-
-/*
- *  run a command with the network connection as standard IO
- */
-static void
-system(Conn *c, char *cmd)
-{
-	int pid;
-	int p;
-	int pfd[2];
-	int n;
-	int wasconsctl;
-	char buf[4096];
-
-	if(pipe(pfd) < 0){
-		perror("pipe");
-		return;
-	}
-	outfd1 = outfd2 = pfd[1];
-
-	wasconsctl = consctl;
-	close(consctl);
-	consctl = -1;
-	switch(pid = fork()){
-	case -1:
-		perror("con");
-		return;
-	case 0:
-		close(pfd[1]);
-		dup(pfd[0], 0);
-		dup(pfd[0], 1);
-		close(c->fd[0]);	/* same as c->fd[1] */
-		close(pfd[0]);
-		if(*cmd)
-			execl("/bin/rc", "rc", "-c", cmd, nil);
-		else
-			execl("/bin/rc", "rc", nil);
-		perror("con");
-		exits("exec");
-		break;
-	default:
-		close(pfd[0]);
-		while((n = read(pfd[1], buf, sizeof(buf))) > 0)
-			sendwritemsg(c, buf, n);
-		p = waitpid();
-		outfd1 = 1;
-		outfd2 = 2;
-		close(pfd[1]);
-		if(p < 0 || p != pid)
-			return;
-		break;
-	}
-	if(wasconsctl >= 0){
-		consctl = open("/dev/consctl", OWRITE);
-		if(consctl < 0)
-			error("cannot open consctl");
-	}
-}
-
-static void
-cookedcatchint(void*, char *msg)
-{
-	if(strstr(msg, "interrupt"))
-		noted(NCONT);
-	else if(strstr(msg, "kill"))
-		noted(NDFLT);
-	else
-		noted(NCONT);
-}
-
-static int
-wasintr(void)
-{
-	char err[64];
-
-	rerrstr(err, sizeof err);
-	return strstr(err, "interrupt") != 0;
-}
-
-void
-fromstdin(Conn *c)
-{
-	int n;
-	char buf[1024];
-	int pid;
-	int eofs;
-
-	switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
-	case -1:
-		error("fork: %r");
-	case 0:
-		break;
-	default:
-		atexitkill(pid);
-		return;
-	}
-
-	atexit(atexitkiller);
-	if(interactive)
-		rawon();
-
-	notify(cookedcatchint);
-
-	eofs = 0;
-	for(;;){
-		n = read(0, buf, sizeof(buf));
-		if(n < 0){
-			if(wasintr()){
-				if(!raw){
-					buf[0] = 0x7f;
-					n = 1;
-				}else
-					continue;
-			}else
-				break;
-		}
-		if(n == 0){
-			if(!c->interactive || ++eofs > 32)
-				break;
-		}else
-			eofs = 0;
-		if(interactive && usemenu && n && memchr(buf, 0x1c, n)) {
-			if(menu(c)=='q'){
-				sendwritemsg(c, "", 0);
-				exits("quit");
-			}
-			continue;
-		}
-		if(!raw && n==0){
-			buf[0] = 0x4;
-			n = 1;
-		}
-		sendwritemsg(c, buf, n);
-	}
-	sendwritemsg(c, "", 0);
-	atexitdont(atexitkiller);
-	exits(nil);
-}
-
-void
-winchanges(Conn *c)
-{
-	int nrow, ncol, width, height;
-	int pid;
-
-	switch(pid = rfork(RFMEM|RFPROC|RFNOWAIT)){
-	case -1:
-		error("fork: %r");
-	case 0:
-		break;
-	default:
-		atexitkill(pid);
-		return;
-	}
-
-	for(;;){
-		if(readgeom(&nrow, &ncol, &width, &height) < 0)
-			break;
-		sendwindowsize(c, nrow, ncol, width, height);
-	}
-	exits(nil);
-}
--- a/sys/src/cmd/ssh/ssh.h
+++ /dev/null
@@ -1,303 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <mp.h>
-#include <auth.h>
-#include <libsec.h>
-
-enum		/* internal debugging flags */
-{
-	DBG=			1<<0,
-	DBG_CRYPTO=		1<<1,
-	DBG_PACKET=		1<<2,
-	DBG_AUTH=		1<<3,
-	DBG_PROC=		1<<4,
-	DBG_PROTO=		1<<5,
-	DBG_IO=			1<<6,
-	DBG_SCP=		1<<7,
-};
-
-enum		/* protocol packet types */
-{
-/* 0 */
-	SSH_MSG_NONE=0,
-	SSH_MSG_DISCONNECT,
-	SSH_SMSG_PUBLIC_KEY,
-	SSH_CMSG_SESSION_KEY,
-	SSH_CMSG_USER,
-	SSH_CMSG_AUTH_RHOSTS,
-	SSH_CMSG_AUTH_RSA,
-	SSH_SMSG_AUTH_RSA_CHALLENGE,
-	SSH_CMSG_AUTH_RSA_RESPONSE,
-	SSH_CMSG_AUTH_PASSWORD,
-
-/* 10 */
-	SSH_CMSG_REQUEST_PTY,
-	SSH_CMSG_WINDOW_SIZE,
-	SSH_CMSG_EXEC_SHELL,
-	SSH_CMSG_EXEC_CMD,
-	SSH_SMSG_SUCCESS,
-	SSH_SMSG_FAILURE,
-	SSH_CMSG_STDIN_DATA,
-	SSH_SMSG_STDOUT_DATA,
-	SSH_SMSG_STDERR_DATA,
-	SSH_CMSG_EOF,
-
-/* 20 */
-	SSH_SMSG_EXITSTATUS,
-	SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
-	SSH_MSG_CHANNEL_OPEN_FAILURE,
-	SSH_MSG_CHANNEL_DATA,
-	SSH_MSG_CHANNEL_INPUT_EOF,
-	SSH_MSG_CHANNEL_OUTPUT_CLOSED,
-	SSH_MSG_UNIX_DOMAIN_X11_FORWARDING,	/* obsolete */
-	SSH_SMSG_X11_OPEN,
-	SSH_CMSG_PORT_FORWARD_REQUEST,
-	SSH_MSG_PORT_OPEN,
-
-/* 30 */
-	SSH_CMSG_AGENT_REQUEST_FORWARDING,
-	SSH_SMSG_AGENT_OPEN,
-	SSH_MSG_IGNORE,
-	SSH_CMSG_EXIT_CONFIRMATION,
-	SSH_CMSG_X11_REQUEST_FORWARDING,
-	SSH_CMSG_AUTH_RHOSTS_RSA,
-	SSH_MSG_DEBUG,
-	SSH_CMSG_REQUEST_COMPRESSION,
-	SSH_CMSG_MAX_PACKET_SIZE,
-	SSH_CMSG_AUTH_TIS,
-
-/* 40 */
-	SSH_SMSG_AUTH_TIS_CHALLENGE,
-	SSH_CMSG_AUTH_TIS_RESPONSE,
-	SSH_CMSG_AUTH_KERBEROS,
-	SSH_SMSG_AUTH_KERBEROS_RESPONSE,
-	SSH_CMSG_HAVE_KERBEROS_TGT,
-};
-
-enum		/* protocol flags */
-{
-	SSH_PROTOFLAG_SCREEN_NUMBER=1<<0,
-	SSH_PROTOFLAG_HOST_IN_FWD_OPEN=1<<1,
-};
-
-enum		/* agent protocol packet types */
-{
-	SSH_AGENTC_NONE = 0,
-	SSH_AGENTC_REQUEST_RSA_IDENTITIES,
-	SSH_AGENT_RSA_IDENTITIES_ANSWER,
-	SSH_AGENTC_RSA_CHALLENGE,
-	SSH_AGENT_RSA_RESPONSE,
-	SSH_AGENT_FAILURE,
-	SSH_AGENT_SUCCESS,
-	SSH_AGENTC_ADD_RSA_IDENTITY,
-	SSH_AGENTC_REMOVE_RSA_IDENTITY,
-};
-
-enum		/* protocol constants */
-{
-	SSH_MAX_DATA = 256*1024,
-	SSH_MAX_MSG = SSH_MAX_DATA+4,
-
-	SESSKEYLEN = 32,
-	SESSIDLEN = 16,
-	
-	COOKIELEN = 8,
-};
-
-enum		/* crypto ids */
-{
-	SSH_CIPHER_NONE = 0,
-	SSH_CIPHER_IDEA,
-	SSH_CIPHER_DES,
-	SSH_CIPHER_3DES,
-	SSH_CIPHER_TSS,
-	SSH_CIPHER_RC4,
-	SSH_CIPHER_BLOWFISH,
-	SSH_CIPHER_TWIDDLE,		/* for debugging */
-};
-
-enum		/* auth method ids */
-{
-	SSH_AUTH_RHOSTS = 1,
-	SSH_AUTH_RSA = 2,
-	SSH_AUTH_PASSWORD = 3,
-	SSH_AUTH_RHOSTS_RSA = 4,
-	SSH_AUTH_TIS = 5,
-	SSH_AUTH_USER_RSA = 6,
-};
-
-typedef struct Auth Auth;
-typedef struct Authsrv Authsrv;
-typedef struct Cipher Cipher;
-typedef struct CipherState CipherState;
-typedef struct Conn Conn;
-typedef struct Msg Msg;
-
-#pragma incomplete CipherState
-
-struct Auth
-{
-	int id;
-	char *name;
-	int (*fn)(Conn*);
-};
-
-struct Authsrv
-{
-	int id;
-	char *name;
-	int firstmsg;
-	AuthInfo *(*fn)(Conn*, Msg*);
-};
-
-struct Cipher
-{
-	int id;
-	char *name;
-	CipherState *(*init)(Conn*, int isserver);
-	void (*encrypt)(CipherState*, uchar*, int);
-	void (*decrypt)(CipherState*, uchar*, int);
-};
-
-struct Conn
-{
-	QLock;
-	int fd[2];
-	CipherState *cstate;
-	uchar cookie[COOKIELEN];
-	uchar sessid[SESSIDLEN];
-	uchar sesskey[SESSKEYLEN];
-	RSApub *serverkey;
-	RSApub *hostkey;
-	ulong flags;
-	ulong ciphermask;
-	Cipher *cipher;		/* chosen cipher */
-	Cipher **okcipher;	/* list of acceptable ciphers */
-	int nokcipher;
-	ulong authmask;
-	Auth **okauth;
-	int nokauth;
-	char *user;
-	char *host;
-	char *aliases;
-	int interactive;
-	Msg *unget;
-
-	RSApriv *serverpriv;		/* server only */
-	RSApriv *hostpriv;
-	Authsrv **okauthsrv;
-	int nokauthsrv;
-};
-
-struct Msg
-{
-	Conn *c;
-	uchar type;
-	ulong len;		/* output: #bytes before pos, input: #bytes after pos */
-	uchar *bp;	/* beginning of allocated space */
-	uchar *rp;		/* read pointer */
-	uchar *wp;	/* write pointer */
-	uchar *ep;	/* end of allocated space */
-	Msg *link;		/* for sshnet */
-};
-
-#define LONG(p)	(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|((p)[3]))
-#define PLONG(p, l) \
-	(((p)[0]=(l)>>24),((p)[1]=(l)>>16),\
-	 ((p)[2]=(l)>>8),((p)[3]=(l)))
-#define SHORT(p) (((p)[0]<<8)|(p)[1])
-#define PSHORT(p,l) \
-	(((p)[0]=(l)>>8),((p)[1]=(l)))
-
-extern char Edecode[];
-extern char Eencode[];
-extern char Ememory[];
-extern char Ehangup[];
-extern int doabort;
-extern int debuglevel;
-
-extern Auth authpassword;
-extern Auth authrsa;
-extern Auth authtis;
-
-extern Authsrv authsrvpassword;
-extern Authsrv authsrvtis;
-
-extern Cipher cipher3des;
-extern Cipher cipherblowfish;
-extern Cipher cipherdes;
-extern Cipher cipherrc4;
-extern Cipher ciphernone;
-extern Cipher ciphertwiddle;
-
-/* msg.c */
-Msg*	allocmsg(Conn*, int, int);
-void		badmsg(Msg*, int);
-Msg*	recvmsg(Conn*, int);
-void		unrecvmsg(Conn*, Msg*);
-int		sendmsg(Msg*);
-uchar	getbyte(Msg*);
-ushort	getshort(Msg*);
-ulong	getlong(Msg*);
-char*	getstring(Msg*);
-void*	getbytes(Msg*, int);
-mpint*	getmpint(Msg*);
-RSApub*	getRSApub(Msg*);
-void		putbyte(Msg*, uchar);
-void		putshort(Msg*, ushort);
-void		putlong(Msg*, ulong);
-void		putstring(Msg*, char*);
-void		putbytes(Msg*, void*, long);
-void		putmpint(Msg*, mpint*);
-void		putRSApub(Msg*, RSApub*);
-mpint*	rsapad(mpint*, int);
-mpint*	rsaunpad(mpint*);
-void		mptoberjust(mpint*, uchar*, int);
-mpint*	rsaencryptbuf(RSApub*, uchar*, int);
-
-/* cmsg.c */
-void		sshclienthandshake(Conn*);
-void		requestpty(Conn*);
-int		readgeom(int*, int*, int*, int*);
-void		sendwindowsize(Conn*, int, int, int, int);
-int		rawhack;
-
-/* smsg.c */
-void		sshserverhandshake(Conn*);
-
-/* pubkey.c */
-enum
-{
-	KeyOk,
-	KeyWrong,
-	NoKey,
-	NoKeyFile,
-};
-int		appendkey(char*, char*, RSApub*);
-int		findkey(char*, char*, RSApub*);
-int		replacekey(char*, char*, RSApub*);
-
-/* agent.c */
-int		startagent(Conn*);
-void		handleagentmsg(Msg*);
-void		handleagentopen(Msg*);
-void		handleagentieof(Msg*);
-void		handleagentoclose(Msg*);
-
-/* util.c */
-void		debug(int, char*, ...);
-void*	emalloc(long);
-void*	erealloc(void*, long);
-void		error(char*, ...);
-RSApriv*	readsecretkey(char*);
-int		readstrnl(int, char*, int);
-void		atexitkill(int);
-void		atexitkiller(void);
-void		calcsessid(Conn*);
-void		sshlog(char*, ...);
-void		setaliases(Conn*, char*);
-void		privatefactotum(void);
-
-#pragma varargck argpos debug 2
-#pragma varargck argpos error 1
-#pragma varargck argpos sshlog 2
--- a/sys/src/cmd/ssh/sshnet.c
+++ /dev/null
@@ -1,1110 +1,0 @@
-/*
- * SSH network file system.
- * Presents remote TCP stack as /net-style file system.
- */
-
-#include "ssh.h"
-#include <bio.h>
-#include <ndb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-
-int rawhack = 1;
-Conn *conn;
-char *remoteip	= "<remote>";
-char *mtpt;
-
-Cipher *allcipher[] = {
-	&cipherrc4,
-	&cipherblowfish,
-	&cipher3des,
-	&cipherdes,
-	&ciphernone,
-	&ciphertwiddle,
-};
-
-Auth *allauth[] = {
-	&authpassword,
-	&authrsa,
-	&authtis,
-};
-
-char *cipherlist = "rc4 3des";
-char *authlist = "rsa password tis";
-
-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;
-}
-
-Auth*
-findauth(char *name, Auth **list, int nlist)
-{
-	int i;
-
-	for(i=0; i<nlist; i++)
-		if(strcmp(name, list[i]->name) == 0)
-			return list[i];
-	error("unknown auth %s", name);
-	return nil;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: sshnet [-A authlist] [-c cipherlist] [-m mtpt] [user@]hostname\n");
-	exits("usage");
-}
-
-int
-isatty(int fd)
-{
-	char buf[64];
-
-	buf[0] = '\0';
-	fd2path(fd, buf, sizeof buf);
-	if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
-		return 1;
-	return 0;
-}
-
-enum
-{
-	Qroot,
-	Qcs,
-	Qtcp,
-	Qclone,
-	Qn,
-	Qctl,
-	Qdata,
-	Qlocal,
-	Qremote,
-	Qstatus,
-};
-
-#define PATH(type, n)		((type)|((n)<<8))
-#define TYPE(path)			((int)(path) & 0xFF)
-#define NUM(path)			((uint)(path)>>8)
-
-Channel *sshmsgchan;		/* chan(Msg*) */
-Channel *fsreqchan;			/* chan(Req*) */
-Channel *fsreqwaitchan;		/* chan(nil) */
-Channel *fsclunkchan;		/* chan(Fid*) */
-Channel *fsclunkwaitchan;	/* chan(nil) */
-ulong time0;
-
-enum
-{
-	Closed,
-	Dialing,
-	Established,
-	Teardown,
-};
-
-char *statestr[] = {
-	"Closed",
-	"Dialing",
-	"Established",
-	"Teardown",
-};
-
-typedef struct Client Client;
-struct Client
-{
-	int ref;
-	int state;
-	int num;
-	int servernum;
-	char *connect;
-	Req *rq;
-	Req **erq;
-	Msg *mq;
-	Msg **emq;
-};
-
-int nclient;
-Client **client;
-
-int
-newclient(void)
-{
-	int i;
-	Client *c;
-
-	for(i=0; i<nclient; i++)
-		if(client[i]->ref==0 && client[i]->state == Closed)
-			return i;
-
-	if(nclient%16 == 0)
-		client = erealloc9p(client, (nclient+16)*sizeof(client[0]));
-
-	c = emalloc9p(sizeof(Client));
-	memset(c, 0, sizeof(*c));
-	c->num = nclient;
-	client[nclient++] = c;
-	return c->num;
-}
-
-void
-queuereq(Client *c, Req *r)
-{
-	if(c->rq==nil)
-		c->erq = &c->rq;
-	*c->erq = r;
-	r->aux = nil;
-	c->erq = (Req**)&r->aux;
-}
-
-void
-queuemsg(Client *c, Msg *m)
-{
-	if(c->mq==nil)
-		c->emq = &c->mq;
-	*c->emq = m;
-	m->link = nil;
-	c->emq = (Msg**)&m->link;
-}
-
-void
-matchmsgs(Client *c)
-{
-	Req *r;
-	Msg *m;
-	int n, rm;
-
-	while(c->rq && c->mq){
-		r = c->rq;
-		c->rq = r->aux;
-
-		rm = 0;
-		m = c->mq;
-		n = r->ifcall.count;
-		if(n >= m->ep - m->rp){
-			n = m->ep - m->rp;
-			c->mq = m->link;
-			rm = 1;
-		}
-		memmove(r->ofcall.data, m->rp, n);
-		if(rm)
-			free(m);
-		else
-			m->rp += n;
-		r->ofcall.count = n;
-		respond(r, nil);
-	}
-}
-
-Req*
-findreq(Client *c, Req *r)
-{
-	Req **l;
-
-	for(l=&c->rq; *l; l=(Req**)&(*l)->aux){
-		if(*l == r){
-			*l = r->aux;
-			if(*l == nil)
-				c->erq = l;
-			return r;
-		}
-	}
-	return nil;
-}
-
-void
-dialedclient(Client *c)
-{
-	Req *r;
-
-	if(r=c->rq){
-		if(r->aux != nil)
-			sysfatal("more than one outstanding dial request (BUG)");
-		if(c->state == Established)
-			respond(r, nil);
-		else
-			respond(r, "connect failed");
-	}
-	c->rq = nil;
-}
-
-void
-teardownclient(Client *c)
-{
-	Msg *m;
-
-	c->state = Teardown;
-	m = allocmsg(conn, SSH_MSG_CHANNEL_INPUT_EOF, 4);
-	putlong(m, c->servernum);
-	sendmsg(m);
-}
-
-void
-hangupclient(Client *c)
-{
-	Req *r, *next;
-	Msg *m, *mnext;
-
-	c->state = Closed;
-	for(m=c->mq; m; m=mnext){
-		mnext = m->link;
-		free(m);
-	}
-	c->mq = nil;
-	for(r=c->rq; r; r=next){
-		next = r->aux;
-		respond(r, "hangup on network connection");
-	}
-	c->rq = nil;
-}
-
-void
-closeclient(Client *c)
-{
-	Msg *m, *next;
-
-	if(--c->ref)
-		return;
-
-	if(c->rq != nil)
-		sysfatal("ref count reached zero with requests pending (BUG)");
-
-	for(m=c->mq; m; m=next){
-		next = m->link;
-		free(m);
-	}
-	c->mq = nil;
-
-	if(c->state != Closed)
-		teardownclient(c);
-}
-
-	
-void
-sshreadproc(void *a)
-{
-	Conn *c;
-	Msg *m;
-
-	c = a;
-	for(;;){
-		m = recvmsg(c, -1);
-		if(m == nil)
-			sysfatal("eof on ssh connection");
-		sendp(sshmsgchan, m);
-	}
-}
-
-typedef struct Tab Tab;
-struct Tab
-{
-	char *name;
-	ulong mode;
-};
-
-Tab tab[] =
-{
-	"/",		DMDIR|0555,
-	"cs",		0666,
-	"tcp",	DMDIR|0555,	
-	"clone",	0666,
-	nil,		DMDIR|0555,
-	"ctl",		0666,
-	"data",	0666,
-	"local",	0444,
-	"remote",	0444,
-	"status",	0444,
-};
-
-static void
-fillstat(Dir *d, uvlong path)
-{
-	Tab *t;
-
-	memset(d, 0, sizeof(*d));
-	d->uid = estrdup9p("ssh");
-	d->gid = estrdup9p("ssh");
-	d->qid.path = path;
-	d->atime = d->mtime = time0;
-	t = &tab[TYPE(path)];
-	if(t->name)
-		d->name = estrdup9p(t->name);
-	else{
-		d->name = smprint("%ud", NUM(path));
-		if(d->name == nil)
-			sysfatal("out of memory");
-	}
-	d->qid.type = t->mode>>24;
-	d->mode = t->mode;
-}
-
-static void
-fsattach(Req *r)
-{
-	if(r->ifcall.aname && r->ifcall.aname[0]){
-		respond(r, "invalid attach specifier");
-		return;
-	}
-	r->fid->qid.path = PATH(Qroot, 0);
-	r->fid->qid.type = QTDIR;
-	r->fid->qid.vers = 0;
-	r->ofcall.qid = r->fid->qid;
-	respond(r, nil);
-}
-
-static void
-fsstat(Req *r)
-{
-	fillstat(&r->d, r->fid->qid.path);
-	respond(r, nil);
-}
-
-static int
-rootgen(int i, Dir *d, void*)
-{
-	i += Qroot+1;
-	if(i <= Qtcp){
-		fillstat(d, i);
-		return 0;
-	}
-	return -1;
-}
-
-static int
-tcpgen(int i, Dir *d, void*)
-{
-	i += Qtcp+1;
-	if(i < Qn){
-		fillstat(d, i);
-		return 0;
-	}
-	i -= Qn;
-	if(i < nclient){
-		fillstat(d, PATH(Qn, i));
-		return 0;
-	}
-	return -1;
-}
-
-static int
-clientgen(int i, Dir *d, void *aux)
-{
-	Client *c;
-
-	c = aux;
-	i += Qn+1;
-	if(i <= Qstatus){
-		fillstat(d, PATH(i, c->num));
-		return 0;
-	}
-	return -1;
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
-	int i, n;
-	char buf[32];
-	ulong path;
-
-	path = fid->qid.path;
-	if(!(fid->qid.type&QTDIR))
-		return "walk in non-directory";
-
-	if(strcmp(name, "..") == 0){
-		switch(TYPE(path)){
-		case Qn:
-			qid->path = PATH(Qtcp, NUM(path));
-			qid->type = tab[Qtcp].mode>>24;
-			return nil;
-		case Qtcp:
-			qid->path = PATH(Qroot, 0);
-			qid->type = tab[Qroot].mode>>24;
-			return nil;
-		case Qroot:
-			return nil;
-		default:
-			return "bug in fswalk1";
-		}
-	}
-
-	i = TYPE(path)+1;
-	for(; i<nelem(tab); i++){
-		if(i==Qn){
-			n = atoi(name);
-			snprint(buf, sizeof buf, "%d", n);
-			if(n < nclient && strcmp(buf, name) == 0){
-				qid->path = PATH(i, n);
-				qid->type = tab[i].mode>>24;
-				return nil;
-			}
-			break;
-		}
-		if(strcmp(name, tab[i].name) == 0){
-			qid->path = PATH(i, NUM(path));
-			qid->type = tab[i].mode>>24;
-			return nil;
-		}
-		if(tab[i].mode&DMDIR)
-			break;
-	}
-	return "directory entry not found";
-}
-
-typedef struct Cs Cs;
-struct Cs
-{
-	char *resp;
-	int isnew;
-};
-
-static int
-ndbfindport(char *p)
-{
-	char *s, *port;
-	int n;
-	static Ndb *db;
-
-	if(*p == '\0')
-		return -1;
-
-	n = strtol(p, &s, 0);
-	if(*s == '\0')
-		return n;
-
-	if(db == nil){
-		db = ndbopen("/lib/ndb/common");
-		if(db == nil)
-			return -1;
-	}
-
-	port = ndbgetvalue(db, nil, "tcp", p, "port", nil);
-	if(port == nil)
-		return -1;
-	n = atoi(port);
-	free(port);
-
-	return n;
-}	
-
-static void
-csread(Req *r)
-{
-	Cs *cs;
-
-	cs = r->fid->aux;
-	if(cs->resp==nil){
-		respond(r, "cs read without write");
-		return;
-	}
-	if(r->ifcall.offset==0){
-		if(!cs->isnew){
-			r->ofcall.count = 0;
-			respond(r, nil);
-			return;
-		}
-		cs->isnew = 0;
-	}
-	readstr(r, cs->resp);
-	respond(r, nil);
-}
-
-static void
-cswrite(Req *r)
-{
-	int port, nf;
-	char err[ERRMAX], *f[4], *s, *ns;
-	Cs *cs;
-
-	cs = r->fid->aux;
-	s = emalloc(r->ifcall.count+1);
-	memmove(s, r->ifcall.data, r->ifcall.count);
-	s[r->ifcall.count] = '\0';
-
-	nf = getfields(s, f, nelem(f), 0, "!");
-	if(nf != 3){
-		free(s);
-		respond(r, "can't translate");
-		return;
-	}
-	if(strcmp(f[0], "tcp") != 0 && strcmp(f[0], "net") != 0){
-		free(s);
-		respond(r, "unknown protocol");
-		return;
-	}
-	port = ndbfindport(f[2]);
-	if(port <= 0){
-		free(s);
-		respond(r, "no translation found");
-		return;
-	}
-
-	ns = smprint("%s/tcp/clone %s!%d", mtpt, f[1], port);
-	if(ns == nil){
-		free(s);
-		rerrstr(err, sizeof err);
-		respond(r, err);
-		return;
-	}
-	free(s);
-	free(cs->resp);
-	cs->resp = ns;
-	cs->isnew = 1;
-	r->ofcall.count = r->ifcall.count;
-	respond(r, nil);
-}
-
-static void
-ctlread(Req *r, Client *c)
-{
-	char buf[32];
-
-	sprint(buf, "%d", c->num);
-	readstr(r, buf);
-	respond(r, nil);
-}
-
-static void
-ctlwrite(Req *r, Client *c)
-{
-	char *f[3], *s;
-	int nf;
-	Msg *m;
-
-	s = emalloc(r->ifcall.count+1);
-	memmove(s, r->ifcall.data, r->ifcall.count);
-	s[r->ifcall.count] = '\0';
-
-	nf = tokenize(s, f, 3);
-	if(nf == 0){
-		free(s);
-		respond(r, nil);
-		return;
-	}
-
-	if(strcmp(f[0], "hangup") == 0){
-		if(c->state != Established)
-			goto Badarg;
-		if(nf != 1)
-			goto Badarg;
-		queuereq(c, r);
-		teardownclient(c);
-	}else if(strcmp(f[0], "connect") == 0){
-		if(c->state != Closed)
-			goto Badarg;
-		if(nf != 2)
-			goto Badarg;
-		c->connect = estrdup9p(f[1]);
-		nf = getfields(f[1], f, nelem(f), 0, "!");
-		if(nf != 2){
-			free(c->connect);
-			c->connect = nil;
-			goto Badarg;
-		}
-		c->state = Dialing;
-		m = allocmsg(conn, SSH_MSG_PORT_OPEN, 4+4+strlen(f[0])+4+4+strlen("localhost"));
-		putlong(m, c->num);
-		putstring(m, f[0]);
-		putlong(m, ndbfindport(f[1]));
-		putstring(m, "localhost");
-		queuereq(c, r);
-		sendmsg(m);
-	}else{
-	Badarg:
-		respond(r, "bad or inappropriate tcp control message");
-	}
-	free(s);
-}
-
-static void
-dataread(Req *r, Client *c)
-{
-	if(c->state != Established){
-		respond(r, "not connected");
-		return;
-	}
-	queuereq(c, r);
-	matchmsgs(c);
-}
-
-static void
-datawrite(Req *r, Client *c)
-{
-	Msg *m;
-
-	if(c->state != Established){
-		respond(r, "not connected");
-		return;
-	}
-	if(r->ifcall.count){
-		m = allocmsg(conn, SSH_MSG_CHANNEL_DATA, 4+4+r->ifcall.count);
-		putlong(m, c->servernum);
-		putlong(m, r->ifcall.count);
-		putbytes(m, r->ifcall.data, r->ifcall.count);
-		sendmsg(m);
-	}
-	r->ofcall.count = r->ifcall.count;
-	respond(r, nil);
-}
-
-static void
-localread(Req *r)
-{
-	char buf[128];
-
-	snprint(buf, sizeof buf, "%s!%d\n", remoteip, 0);
-	readstr(r, buf);
-	respond(r, nil);
-}
-
-static void
-remoteread(Req *r, Client *c)
-{
-	char *s;
-	char buf[128];
-
-	s = c->connect;
-	if(s == nil)
-		s = "::!0";
-	snprint(buf, sizeof buf, "%s\n", s);
-	readstr(r, buf);
-	respond(r, nil);
-}
-
-static void
-statusread(Req *r, Client *c)
-{
-	char buf[64];
-	char *s;
-
-	snprint(buf, sizeof buf, "%s!%d", remoteip, 0);
-	s = statestr[c->state];
-	readstr(r, s);
-	respond(r, nil);
-}
-
-static void
-fsread(Req *r)
-{
-	char e[ERRMAX];
-	ulong path;
-
-	path = r->fid->qid.path;
-	switch(TYPE(path)){
-	default:
-		snprint(e, sizeof e, "bug in fsread path=%lux", path);
-		respond(r, e);
-		break;
-
-	case Qroot:
-		dirread9p(r, rootgen, nil);
-		respond(r, nil);
-		break;
-
-	case Qcs:
-		csread(r);
-		break;
-
-	case Qtcp:
-		dirread9p(r, tcpgen, nil);
-		respond(r, nil);
-		break;
-
-	case Qn:
-		dirread9p(r, clientgen, client[NUM(path)]);
-		respond(r, nil);
-		break;
-
-	case Qctl:
-		ctlread(r, client[NUM(path)]);
-		break;
-
-	case Qdata:
-		dataread(r, client[NUM(path)]);
-		break;
-
-	case Qlocal:
-		localread(r);
-		break;
-
-	case Qremote:
-		remoteread(r, client[NUM(path)]);
-		break;
-
-	case Qstatus:
-		statusread(r, client[NUM(path)]);
-		break;
-	}
-}
-
-static void
-fswrite(Req *r)
-{
-	ulong path;
-	char e[ERRMAX];
-
-	path = r->fid->qid.path;
-	switch(TYPE(path)){
-	default:
-		snprint(e, sizeof e, "bug in fswrite path=%lux", path);
-		respond(r, e);
-		break;
-
-	case Qcs:
-		cswrite(r);
-		break;
-
-	case Qctl:
-		ctlwrite(r, client[NUM(path)]);
-		break;
-
-	case Qdata:
-		datawrite(r, client[NUM(path)]);
-		break;
-	}
-}
-
-static void
-fsopen(Req *r)
-{
-	static int need[4] = { 4, 2, 6, 1 };
-	ulong path;
-	int n;
-	Tab *t;
-	Cs *cs;
-
-	/*
-	 * lib9p already handles the blatantly obvious.
-	 * we just have to enforce the permissions we have set.
-	 */
-	path = r->fid->qid.path;
-	t = &tab[TYPE(path)];
-	n = need[r->ifcall.mode&3];
-	if((n&t->mode) != n){
-		respond(r, "permission denied");
-		return;
-	}
-
-	switch(TYPE(path)){
-	case Qcs:
-		cs = emalloc(sizeof(Cs));
-		r->fid->aux = cs;
-		respond(r, nil);
-		break;
-	case Qclone:
-		n = newclient();
-		path = PATH(Qctl, n);
-		r->fid->qid.path = path;
-		r->ofcall.qid.path = path;
-		if(chatty9p)
-			fprint(2, "open clone => path=%lux\n", path);
-		t = &tab[Qctl];
-		/* fall through */
-	default:
-		if(t-tab >= Qn)
-			client[NUM(path)]->ref++;
-		respond(r, nil);
-		break;
-	}
-}
-
-static void
-fsflush(Req *r)
-{
-	int i;
-
-	for(i=0; i<nclient; i++)
-		if(findreq(client[i], r->oldreq))
-			respond(r->oldreq, "interrupted");
-	respond(r, nil);
-}
-
-static void
-handlemsg(Msg *m)
-{
-	int chan, n;
-	Client *c;
-
-	switch(m->type){
-	case SSH_MSG_DISCONNECT:
-	case SSH_CMSG_EXIT_CONFIRMATION:
-		sysfatal("disconnect");
-
-	case SSH_CMSG_STDIN_DATA:
-	case SSH_CMSG_EOF:
-	case SSH_CMSG_WINDOW_SIZE:
-		/* don't care */
-		free(m);
-		break;
-
-	case SSH_MSG_CHANNEL_DATA:
-		chan = getlong(m);
-		n = getlong(m);
-		if(m->rp+n != m->ep)
-			sysfatal("got bad channel data");
-		if(chan<nclient && (c=client[chan])->state==Established){
-			queuemsg(c, m);
-			matchmsgs(c);
-		}else
-			free(m);
-		break;
-
-	case SSH_MSG_CHANNEL_INPUT_EOF:
-		chan = getlong(m);
-		free(m);
-		if(chan<nclient){
-			c = client[chan];
-			chan = c->servernum;
-			hangupclient(c);
-			m = allocmsg(conn, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
-			putlong(m, chan);
-			sendmsg(m);
-		}
-		break;
-
-	case SSH_MSG_CHANNEL_OUTPUT_CLOSED:
-		chan = getlong(m);
-		if(chan<nclient)
-			hangupclient(client[chan]);
-		free(m);
-		break;
-
-	case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
-		chan = getlong(m);
-		c = nil;
-		if(chan>=nclient || (c=client[chan])->state != Dialing){
-			if(c)
-				fprint(2, "cstate %d\n", c->state);
-			sysfatal("got unexpected open confirmation for %d", chan);
-		}
-		c->servernum = getlong(m);
-		c->state = Established;
-		dialedclient(c);
-		free(m);
-		break;
-
-	case SSH_MSG_CHANNEL_OPEN_FAILURE:
-		chan = getlong(m);
-		c = nil;
-		if(chan>=nclient || (c=client[chan])->state != Dialing)
-			sysfatal("got unexpected open failure");
-		if(m->rp+4 <= m->ep)
-			c->servernum = getlong(m);
-		c->state = Closed;
-		dialedclient(c);
-		free(m);
-		break;
-	}
-}
-
-void
-fsnetproc(void*)
-{
-	ulong path;
-	Alt a[4];
-	Cs *cs;
-	Fid *fid;
-	Req *r;
-	Msg *m;
-
-	threadsetname("fsthread");
-
-	a[0].op = CHANRCV;
-	a[0].c = fsclunkchan;
-	a[0].v = &fid;
-	a[1].op = CHANRCV;
-	a[1].c = fsreqchan;
-	a[1].v = &r;
-	a[2].op = CHANRCV;
-	a[2].c = sshmsgchan;
-	a[2].v = &m;
-	a[3].op = CHANEND;
-
-	for(;;){
-		switch(alt(a)){
-		case 0:
-			path = fid->qid.path;
-			switch(TYPE(path)){
-			case Qcs:
-				cs = fid->aux;
-				if(cs){
-					free(cs->resp);
-					free(cs);
-				}
-				break;
-			}
-			if(fid->omode != -1 && TYPE(path) >= Qn)
-				closeclient(client[NUM(path)]);
-			sendp(fsclunkwaitchan, nil);
-			break;
-		case 1:
-			switch(r->ifcall.type){
-			case Tattach:
-				fsattach(r);
-				break;
-			case Topen:
-				fsopen(r);
-				break;
-			case Tread:
-				fsread(r);
-				break;
-			case Twrite:
-				fswrite(r);
-				break;
-			case Tstat:
-				fsstat(r);
-				break;
-			case Tflush:
-				fsflush(r);
-				break;
-			default:
-				respond(r, "bug in fsthread");
-				break;
-			}
-			sendp(fsreqwaitchan, 0);
-			break;
-		case 2:
-			handlemsg(m);
-			break;
-		}
-	}
-}
-
-static void
-fssend(Req *r)
-{
-	sendp(fsreqchan, r);
-	recvp(fsreqwaitchan);	/* avoids need to deal with spurious flushes */
-}
-
-static void
-fsdestroyfid(Fid *fid)
-{
-	sendp(fsclunkchan, fid);
-	recvp(fsclunkwaitchan);
-}
-
-void
-takedown(Srv*)
-{
-	threadexitsall("done");
-}
-
-Srv fs = 
-{
-.attach=		fssend,
-.destroyfid=	fsdestroyfid,
-.walk1=		fswalk1,
-.open=		fssend,
-.read=		fssend,
-.write=		fssend,
-.stat=		fssend,
-.flush=		fssend,
-.end=		takedown,
-};
-
-void
-threadmain(int argc, char **argv)
-{
-	int i, fd;
-	char *host, *user, *p, *service;
-	char *f[16];
-	Msg *m;
-	static Conn c;
-
-	fmtinstall('B', mpfmt);
-	fmtinstall('H', encodefmt);
-
-	mtpt = "/net";
-	service = nil;
-	user = nil;
-	ARGBEGIN{
-	case 'B':	/* undocumented, debugging */
-		doabort = 1;
-		break;
-	case 'D':	/* undocumented, debugging */
-		debuglevel = strtol(EARGF(usage()), nil, 0);
-		break;
-	case '9':	/* undocumented, debugging */
-		chatty9p++;
-		break;
-
-	case 'A':
-		authlist = EARGF(usage());
-		break;
-	case 'c':
-		cipherlist = EARGF(usage());
-		break;
-	case 'm':
-		mtpt = EARGF(usage());
-		break;
-	case 's':
-		service = EARGF(usage());
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc != 1)
-		usage();
-
-	host = argv[0];
-
-	if((p = strchr(host, '@')) != nil){
-		*p++ = '\0';
-		user = host;
-		host = p;
-	}
-	if(user == nil)
-		user = getenv("user");
-	if(user == nil)
-		sysfatal("cannot find user name");
-
-	privatefactotum();
-
-	if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0)
-		sysfatal("dialing %s: %r", host);
-
-	c.interactive = isatty(0);
-	c.fd[0] = c.fd[1] = fd;
-	c.user = user;
-	c.host = host;
-	setaliases(&c, host);
-
-	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.nokauth = getfields(authlist, f, nelem(f), 1, ", ");
-	c.okauth = emalloc(sizeof(Auth*)*c.nokauth);
-	for(i=0; i<c.nokauth; i++)
-		c.okauth[i] = findauth(f[i], allauth, nelem(allauth));
-
-	sshclienthandshake(&c);
-
-	requestpty(&c);		/* turns on TCP_NODELAY on other side */
-	m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0);
-	sendmsg(m);
-
-	time0 = time(0);
-	sshmsgchan = chancreate(sizeof(Msg*), 16);
-	fsreqchan = chancreate(sizeof(Req*), 0);
-	fsreqwaitchan = chancreate(sizeof(void*), 0);
-	fsclunkchan = chancreate(sizeof(Fid*), 0);
-	fsclunkwaitchan = chancreate(sizeof(void*), 0);
-
-	conn = &c;
-	procrfork(sshreadproc, &c, 8192, RFNAMEG|RFNOTEG);
-	procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG);
-
-	threadpostmountsrv(&fs, service, mtpt, MREPL);
-	exits(0);
-}
-
--- a/sys/src/cmd/ssh/sshserve.c
+++ /dev/null
@@ -1,315 +1,0 @@
-#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];
-}
--- a/sys/src/cmd/ssh/util.c
+++ /dev/null
@@ -1,269 +1,0 @@
-#include "ssh.h"
-#include <bio.h>
-#include <ndb.h>
-
-char Edecode[] = "error decoding input packet";
-char Eencode[] = "out of space encoding output packet (BUG)";
-char Ehangup[] = "hungup connection";
-char Ememory[] = "out of memory";
-
-int debuglevel;
-int doabort;
-
-void
-error(char *fmt, ...)
-{
-	va_list arg;
-	char buf[2048];
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-	fprint(2, "%s: %s\n", argv0, buf);
-	if(doabort)
-		abort();
-	exits(buf);
-}
-
-void
-debug(int level, char *fmt, ...)
-{
-	va_list arg;
-
-	if((level&debuglevel) == 0)
-		return;
-	va_start(arg, fmt);
-	vfprint(2, fmt, arg);
-	va_end(arg);
-}
-
-void*
-emalloc(long n)
-{
-	void *a;
-
-	a = mallocz(n, 1);
-	if(a == nil)
-		error(Ememory);
-	setmalloctag(a, getcallerpc(&n));
-	return a;
-}
-
-void*
-erealloc(void *v, long n)
-{
-	v = realloc(v, n);
-	if(v == nil)
-		error(Ememory);
-	setrealloctag(v, getcallerpc(&v));
-	return v;
-}
-
-
-static int killpid[32];
-static int nkillpid;
-void
-atexitkiller(void)
-{
-	int i, pid;
-
-	pid = getpid();
-	debug(DBG, "atexitkiller: nkillpid=%d mypid=%d\n", nkillpid, pid);
-	for(i=0; i<nkillpid; i++)
-		if(pid != killpid[i]){
-			debug(DBG, "killing %d\n", killpid[i]);
-			postnote(PNPROC, killpid[i], "kill");
-		}
-}
-void
-atexitkill(int pid)
-{
-	killpid[nkillpid++] = pid;
-}
-
-int
-readstrnl(int fd, char *buf, int nbuf)
-{
-	int i;
-
-	for(i=0; i<nbuf; i++){
-		switch(read(fd, buf+i, 1)){
-		case -1:
-			return -1;
-		case 0:
-			werrstr("unexpected EOF");
-			return -1;
-		default:
-			if(buf[i]=='\n'){
-				buf[i] = '\0';
-				return 0;
-			}
-			break;
-		}
-	}
-	werrstr("line too long");
-	return -1;
-}
-
-void
-calcsessid(Conn *c)
-{
-	int n;
-	uchar buf[1024];
-
-	n = mptobe(c->hostkey->n, buf, sizeof buf, nil);
-	n += mptobe(c->serverkey->n, buf+n, sizeof buf-n, nil);
-	memmove(buf+n, c->cookie, COOKIELEN);
-	n += COOKIELEN;
-	md5(buf, n, c->sessid, nil);
-}
-
-void
-sshlog(char *f, ...)
-{
-	char *s;
-	va_list arg;
-	Fmt fmt;
-	static int pid;
-
-	if(pid == 0)
-		pid = getpid();
-
-	va_start(arg, f);
-	va_end(arg);
-
-	if(fmtstrinit(&fmt) < 0)
-		sysfatal("fmtstrinit: %r");
-
-	fmtprint(&fmt, "[%d] ", pid);
-	fmtvprint(&fmt, f, arg);
-
-	s = fmtstrflush(&fmt);
-	if(s == nil)
-		sysfatal("fmtstrflush: %r");
-	syslog(0, "ssh", "%s", s);
-	free(s);
-}
-
-/*
- * this is far too smart.
- */
-static int
-pstrcmp(const void *a, const void *b)
-{
-	return strcmp(*(char**)a, *(char**)b);
-}
-
-static char*
-trim(char *s)
-{
-	char *t;
-	int i, last, n, nf;
-	char **f;
-	char *p;
-
-	t = emalloc(strlen(s)+1);
-	t[0] = '\0';
-	n = 1;
-	for(p=s; *p; p++)
-		if(*p == ' ')
-			n++;
-	f = emalloc((n+1)*sizeof(f[0]));
-	nf = tokenize(s, f, n+1);
-	qsort(f, nf, sizeof(f[0]), pstrcmp);
-	last=-1;
-	for(i=0; i<nf; i++){
-		if(last==-1 || strcmp(f[last], f[i])!=0){
-			if(last >= 0)
-				strcat(t, ",");
-			strcat(t, f[i]);
-			last = i;
-		}
-	}
-	return t;	
-}
-
-static void
-usetuple(Conn *c, Ndbtuple *t, int scanentries)
-{
-	int first;
-	Ndbtuple *l, *e;
-	char *s;
-
-	first=1;
-	s = c->host;
-	for(l=t; first||l!=t; l=l->line, first=0){
-		if(scanentries){
-			for(e=l; e; e=e->entry){
-				if(strcmp(e->val, c->host) != 0 &&
-				  (strcmp(e->attr, "ip")==0 || strcmp(e->attr, "dom")==0 || strcmp(e->attr, "sys")==0)){
-					s = smprint("%s %s", s, e->val);
-					if(s == nil)
-						error("out of memory");
-				}
-			}
-		}
-		if(strcmp(l->val, c->host) != 0 &&
-		  (strcmp(l->attr, "ip")==0 || strcmp(l->attr, "dom")==0 || strcmp(l->attr, "sys")==0)){
-			s = smprint("%s %s", s, l->val);
-			if(s == nil)
-				error("out of memory");
-		}
-	}
-	s = trim(s);
-	c->aliases = s;
-}
-
-void
-setaliases(Conn *c, char *name)
-{
-	char *p, *net;
-	char *attr[2];
-	Ndbtuple *t;
-
-	net = "/net";
-	if(name[0]=='/'){
-		p = strchr(name+1, '/');
-		if(p){
-			net = emalloc(p-name+1);
-			memmove(net, name, p-name);
-		}
-	}
-	if(p = strchr(name, '!'))
-		name = p+1;
-
-	c->host = emalloc(strlen(name)+1);
-	strcpy(c->host, name);
-
-	c->aliases = c->host;
-	attr[0] = "dom";
-	attr[1] = "ip";
-	t = csipinfo(nil, ipattr(name), name, attr, 2);
-	if(t != nil){
-		usetuple(c, t, 0);
-		ndbfree(t);
-	}else{
-		t = dnsquery(net, name, "ip");
-		if(t != nil){
-			usetuple(c, t, 1);
-			ndbfree(t);
-		}
-	}
-}
-
-void
-privatefactotum(void)
-{
-	char *user;
-	Dir *d;
-
-	if((user=getuser()) && (d=dirstat("/mnt/factotum/rpc")) && strcmp(user, d->uid)!=0){
-		/* grab the terminal's factotum */
-		rfork(RFNAMEG);	/* was RFNOTEG, which makes little sense */
-		if(access("/mnt/term/mnt/factotum", AEXIST) >= 0){
-//			fprint(2, "binding terminal's factotum\n");
-			if(bind("/mnt/term/mnt/factotum", "/mnt/factotum", MREPL) < 0)
-				sysfatal("cannot find factotum");
-		}
-	}
-}