ref: dc8c7bf2b73d608ac2483aee303a51a3507b4c5a
parent: cb1555c7d741fa482c339aa9ac8a44753e2ad296
author: khm <devnull@localhost>
date: Thu Jan 12 11:36:38 EST 2017
ssh: R.I.P.
--- 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");
- }
- }
-}